asda?‰PNG  IHDR ? f ??C1 sRGB ??é gAMA ±? üa pHYs ? ??o¨d GIDATx^íüL”÷e÷Y?a?("Bh?_ò???¢§?q5k?*:t0A-o??¥]VkJ¢M??f?±8\k2íll£1]q?ù???T PKpge[$$ ebtables.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "ebtables" ] import os.path from firewall.core.prog import runProg from firewall.core.logger import log from firewall.functions import tempFile, readfile, splitArgs from firewall.config import COMMANDS from firewall.core import ipXtables # some common stuff lives there from firewall.errors import FirewallError, INVALID_IPV import string BUILT_IN_CHAINS = { "broute": [ "BROUTING" ], "nat": [ "PREROUTING", "POSTROUTING", "OUTPUT" ], "filter": [ "INPUT", "OUTPUT", "FORWARD" ], } DEFAULT_RULES = { } LOG_RULES = { } OUR_CHAINS = {} # chains created by firewalld for table in BUILT_IN_CHAINS.keys(): DEFAULT_RULES[table] = [ ] OUR_CHAINS[table] = set() for chain in BUILT_IN_CHAINS[table]: DEFAULT_RULES[table].append("-N %s_direct" % chain) DEFAULT_RULES[table].append("-I %s 1 -j %s_direct" % (chain, chain)) DEFAULT_RULES[table].append("-I %s_direct 1 -j RETURN" % chain) OUR_CHAINS[table].add("%s_direct" % chain) class ebtables(object): ipv = "eb" name = "ebtables" policies_supported = False # ebtables only supported with direct interface def __init__(self): self._command = COMMANDS[self.ipv] self._restore_command = COMMANDS["%s-restore" % self.ipv] self.restore_noflush_option = self._detect_restore_noflush_option() self.concurrent_option = self._detect_concurrent_option() self.fill_exists() self.available_tables = [] def fill_exists(self): self.command_exists = os.path.exists(self._command) self.restore_command_exists = os.path.exists(self._restore_command) def _detect_concurrent_option(self): # Do not change any rules, just try to use the --concurrent option # with -L concurrent_option = "" ret = runProg(self._command, ["--concurrent", "-L"]) if ret[0] == 0: concurrent_option = "--concurrent" # concurrent for ebtables lock return concurrent_option def _detect_restore_noflush_option(self): # Do not change any rules, just try to use the restore command # with --noflush rules = [ ] try: self.set_rules(rules, "off") except ValueError: return False return True def __run(self, args): # convert to string list _args = [ ] if self.concurrent_option and self.concurrent_option not in args: _args.append(self.concurrent_option) _args += ["%s" % item for item in args] log.debug2("%s: %s %s", self.__class__, self._command, " ".join(_args)) (status, ret) = runProg(self._command, _args) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._command, " ".join(args), ret)) return ret def _rule_validate(self, rule): for str in ["%%REJECT%%", "%%ICMP%%", "%%LOGTYPE%%"]: if str in rule: raise FirewallError(INVALID_IPV, "'%s' invalid for ebtables" % str) def is_chain_builtin(self, ipv, table, chain): return table in BUILT_IN_CHAINS and \ chain in BUILT_IN_CHAINS[table] def build_chain_rules(self, add, table, chain): rules = [] if add: rules.append([ "-t", table, "-N", chain ]) rules.append([ "-t", table, "-I", chain, "1", "-j", "RETURN" ]) else: rules.append([ "-t", table, "-X", chain ]) return rules def build_rule(self, add, table, chain, index, args): rule = [ "-t", table ] if add: rule += [ "-I", chain, str(index) ] else: rule += [ "-D", chain ] rule += args return rule def reverse_rule(self, args): return ipXtables.common_reverse_rule(args) def check_passthrough(self, args): ipXtables.common_check_passthrough(args) def reverse_passthrough(self, args): return ipXtables.common_reverse_passthrough(args) def set_rules(self, rules, log_denied): temp_file = tempFile() table = "filter" table_rules = { } for _rule in rules: rule = _rule[:] self._rule_validate(rule) # get table form rule for opt in [ "-t", "--table" ]: try: i = rule.index(opt) except ValueError: pass else: if len(rule) >= i+1: rule.pop(i) table = rule.pop(i) # we can not use joinArgs here, because it would use "'" instead # of '"' for the start and end of the string, this breaks # iptables-restore for i in range(len(rule)): for c in string.whitespace: if c in rule[i] and not (rule[i].startswith('"') and rule[i].endswith('"')): rule[i] = '"%s"' % rule[i] table_rules.setdefault(table, []).append(rule) for table in table_rules: temp_file.write("*%s\n" % table) for rule in table_rules[table]: temp_file.write(" ".join(rule) + "\n") temp_file.close() stat = os.stat(temp_file.name) log.debug2("%s: %s %s", self.__class__, self._restore_command, "%s: %d" % (temp_file.name, stat.st_size)) args = [ ] args.append("--noflush") (status, ret) = runProg(self._restore_command, args, stdin=temp_file.name) if log.getDebugLogLevel() > 2: lines = readfile(temp_file.name) if lines is not None: i = 1 for line in lines: log.debug3("%8d: %s" % (i, line), nofmt=1, nl=0) if not line.endswith("\n"): log.debug3("", nofmt=1) i += 1 os.unlink(temp_file.name) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._restore_command, " ".join(args), ret)) def set_rule(self, rule, log_denied): self._rule_validate(rule) return self.__run(rule) def get_available_tables(self, table=None): ret = [] tables = [ table ] if table else BUILT_IN_CHAINS.keys() for table in tables: if table in self.available_tables: ret.append(table) else: try: self.__run(["-t", table, "-L"]) self.available_tables.append(table) ret.append(table) except ValueError: log.debug1("ebtables table '%s' does not exist." % table) return ret def get_zone_table_chains(self, table): return {} def build_flush_rules(self): rules = [] for table in BUILT_IN_CHAINS.keys(): if table not in self.get_available_tables(): continue # Flush firewall rules: -F # Delete firewall chains: -X # Set counter to zero: -Z for flag in [ "-F", "-X", "-Z" ]: rules.append(["-t", table, flag]) return rules def build_set_policy_rules(self, policy): rules = [] _policy = "DROP" if policy == "PANIC" else policy for table in BUILT_IN_CHAINS.keys(): if table not in self.get_available_tables(): continue for chain in BUILT_IN_CHAINS[table]: rules.append(["-t", table, "-P", chain, _policy]) return rules def build_default_tables(self): # nothing to do, they always exist return [] def build_default_rules(self, log_denied="off"): default_rules = [] for table in DEFAULT_RULES: if table not in self.get_available_tables(): continue _default_rules = DEFAULT_RULES[table][:] if log_denied != "off" and table in LOG_RULES: _default_rules.extend(LOG_RULES[table]) prefix = [ "-t", table ] for rule in _default_rules: if type(rule) == list: default_rules.append(prefix + rule) else: default_rules.append(prefix + splitArgs(rule)) return default_rules def is_ipv_supported(self, ipv): return ipv == self.ipv PKpge[ fw_config.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "FirewallConfig" ] import copy import os import os.path import shutil from firewall import config from firewall.core.logger import log from firewall.core.io.icmptype import IcmpType, icmptype_reader, icmptype_writer from firewall.core.io.service import Service, service_reader, service_writer from firewall.core.io.zone import Zone, zone_reader, zone_writer from firewall.core.io.ipset import IPSet, ipset_reader, ipset_writer from firewall.core.io.helper import Helper, helper_reader, helper_writer from firewall.core.io.policy import Policy, policy_reader, policy_writer from firewall import errors from firewall.errors import FirewallError class FirewallConfig(object): def __init__(self, fw): self._fw = fw self.__init_vars() def __repr__(self): return '%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)' % \ (self.__class__, self._ipsets, self._icmptypes, self._services, self._zones, self._helpers, self.policy_objects, self._builtin_ipsets, self._builtin_icmptypes, self._builtin_services, self._builtin_zones, self._builtin_helpers, self._builtin_policy_objects, self._firewalld_conf, self._policies, self._direct) def __init_vars(self): self._ipsets = { } self._icmptypes = { } self._services = { } self._zones = { } self._helpers = { } self._policy_objects = { } self._builtin_ipsets = { } self._builtin_icmptypes = { } self._builtin_services = { } self._builtin_zones = { } self._builtin_helpers = { } self._builtin_policy_objects = { } self._firewalld_conf = None self._policies = None self._direct = None def cleanup(self): for x in list(self._builtin_ipsets.keys()): self._builtin_ipsets[x].cleanup() del self._builtin_ipsets[x] for x in list(self._ipsets.keys()): self._ipsets[x].cleanup() del self._ipsets[x] for x in list(self._builtin_icmptypes.keys()): self._builtin_icmptypes[x].cleanup() del self._builtin_icmptypes[x] for x in list(self._icmptypes.keys()): self._icmptypes[x].cleanup() del self._icmptypes[x] for x in list(self._builtin_services.keys()): self._builtin_services[x].cleanup() del self._builtin_services[x] for x in list(self._services.keys()): self._services[x].cleanup() del self._services[x] for x in list(self._builtin_zones.keys()): self._builtin_zones[x].cleanup() del self._builtin_zones[x] for x in list(self._zones.keys()): self._zones[x].cleanup() del self._zones[x] for x in list(self._builtin_helpers.keys()): self._builtin_helpers[x].cleanup() del self._builtin_helpers[x] for x in list(self._helpers.keys()): self._helpers[x].cleanup() del self._helpers[x] if self._firewalld_conf: self._firewalld_conf.cleanup() del self._firewalld_conf self._firewalld_conf = None if self._policies: self._policies.cleanup() del self._policies self._policies = None if self._direct: self._direct.cleanup() del self._direct self._direct = None self.__init_vars() # access check def lockdown_enabled(self): return self._fw.policies.query_lockdown() def access_check(self, key, value): return self._fw.policies.access_check(key, value) # firewalld_conf def set_firewalld_conf(self, conf): self._firewalld_conf = conf def get_firewalld_conf(self): return self._firewalld_conf def update_firewalld_conf(self): if not os.path.exists(config.FIREWALLD_CONF): self._firewalld_conf.clear() else: self._firewalld_conf.read() # policies def set_policies(self, policies): self._policies = policies def get_policies(self): return self._policies def update_lockdown_whitelist(self): if not os.path.exists(config.LOCKDOWN_WHITELIST): self._policies.lockdown_whitelist.cleanup() else: self._policies.lockdown_whitelist.read() # direct def set_direct(self, direct): self._direct = direct def get_direct(self): return self._direct def update_direct(self): if not os.path.exists(config.FIREWALLD_DIRECT): self._direct.cleanup() else: self._direct.read() # ipset def get_ipsets(self): return sorted(set(list(self._ipsets.keys()) + \ list(self._builtin_ipsets.keys()))) def add_ipset(self, obj): if obj.builtin: self._builtin_ipsets[obj.name] = obj else: self._ipsets[obj.name] = obj def get_ipset(self, name): if name in self._ipsets: return self._ipsets[name] elif name in self._builtin_ipsets: return self._builtin_ipsets[name] raise FirewallError(errors.INVALID_IPSET, name) def load_ipset_defaults(self, obj): if obj.name not in self._ipsets: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._ipsets[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._ipsets[%s] != obj" % obj.name) elif obj.name not in self._builtin_ipsets: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in ipset" % obj.name) self._remove_ipset(obj) return self._builtin_ipsets[obj.name] def get_ipset_config(self, obj): return obj.export_config() def set_ipset_config(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.import_config(conf) x.path = config.ETC_FIREWALLD_IPSETS x.builtin = False if obj.path != x.path: x.default = False self.add_ipset(x) ipset_writer(x) return x else: obj.import_config(conf) ipset_writer(obj) return obj def new_ipset(self, name, conf): if name in self._ipsets or name in self._builtin_ipsets: raise FirewallError(errors.NAME_CONFLICT, "new_ipset(): '%s'" % name) x = IPSet() x.check_name(name) x.import_config(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_IPSETS # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True ipset_writer(x) self.add_ipset(x) return x def update_ipset_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path == config.ETC_FIREWALLD_IPSETS: # removed custom ipset for x in self._ipsets.keys(): obj = self._ipsets[x] if obj.filename == filename: del self._ipsets[x] if obj.name in self._builtin_ipsets: return ("update", self._builtin_ipsets[obj.name]) return ("remove", obj) else: # removed builtin ipset for x in self._builtin_ipsets.keys(): obj = self._builtin_ipsets[x] if obj.filename == filename: del self._builtin_ipsets[x] if obj.name not in self._ipsets: # update dbus ipset return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # ipset not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading ipset file '%s'", name) try: obj = ipset_reader(filename, path) except Exception as msg: log.error("Failed to load ipset file '%s': %s", filename, msg) return (None, None) # new ipset if obj.name not in self._builtin_ipsets and obj.name not in self._ipsets: self.add_ipset(obj) return ("new", obj) # updated ipset if path == config.ETC_FIREWALLD_IPSETS: # custom ipset update if obj.name in self._ipsets: obj.default = self._ipsets[obj.name].default self._ipsets[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_ipsets: # builtin ipset update del self._builtin_ipsets[obj.name] self._builtin_ipsets[obj.name] = obj if obj.name not in self._ipsets: # update dbus ipset return ("update", obj) else: # builtin hidden, no update needed return (None, None) # ipset not known to firewalld, yet (timeout, ..) return (None, None) def _remove_ipset(self, obj): if obj.name not in self._ipsets: raise FirewallError(errors.INVALID_IPSET, obj.name) if obj.path != config.ETC_FIREWALLD_IPSETS: raise FirewallError(errors.INVALID_DIRECTORY, "'%s' != '%s'" % (obj.path, config.ETC_FIREWALLD_IPSETS)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._ipsets[obj.name] def check_builtin_ipset(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_IPSET, "'%s' is built-in ipset" % obj.name) def remove_ipset(self, obj): self.check_builtin_ipset(obj) self._remove_ipset(obj) def rename_ipset(self, obj, name): self.check_builtin_ipset(obj) new_ipset = self._copy_ipset(obj, name) self._remove_ipset(obj) return new_ipset def _copy_ipset(self, obj, name): return self.new_ipset(name, obj.export_config()) # icmptypes def get_icmptypes(self): return sorted(set(list(self._icmptypes.keys()) + \ list(self._builtin_icmptypes.keys()))) def add_icmptype(self, obj): if obj.builtin: self._builtin_icmptypes[obj.name] = obj else: self._icmptypes[obj.name] = obj def get_icmptype(self, name): if name in self._icmptypes: return self._icmptypes[name] elif name in self._builtin_icmptypes: return self._builtin_icmptypes[name] raise FirewallError(errors.INVALID_ICMPTYPE, name) def load_icmptype_defaults(self, obj): if obj.name not in self._icmptypes: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._icmptypes[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._icmptypes[%s] != obj" % obj.name) elif obj.name not in self._builtin_icmptypes: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in icmptype" % obj.name) self._remove_icmptype(obj) return self._builtin_icmptypes[obj.name] def get_icmptype_config(self, obj): return obj.export_config() def set_icmptype_config(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.import_config(conf) x.path = config.ETC_FIREWALLD_ICMPTYPES x.builtin = False if obj.path != x.path: x.default = False self.add_icmptype(x) icmptype_writer(x) return x else: obj.import_config(conf) icmptype_writer(obj) return obj def new_icmptype(self, name, conf): if name in self._icmptypes or name in self._builtin_icmptypes: raise FirewallError(errors.NAME_CONFLICT, "new_icmptype(): '%s'" % name) x = IcmpType() x.check_name(name) x.import_config(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_ICMPTYPES # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True icmptype_writer(x) self.add_icmptype(x) return x def update_icmptype_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path == config.ETC_FIREWALLD_ICMPTYPES: # removed custom icmptype for x in self._icmptypes.keys(): obj = self._icmptypes[x] if obj.filename == filename: del self._icmptypes[x] if obj.name in self._builtin_icmptypes: return ("update", self._builtin_icmptypes[obj.name]) return ("remove", obj) else: # removed builtin icmptype for x in self._builtin_icmptypes.keys(): obj = self._builtin_icmptypes[x] if obj.filename == filename: del self._builtin_icmptypes[x] if obj.name not in self._icmptypes: # update dbus icmptype return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # icmptype not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading icmptype file '%s'", name) try: obj = icmptype_reader(filename, path) except Exception as msg: log.error("Failed to load icmptype file '%s': %s", filename, msg) return (None, None) # new icmptype if obj.name not in self._builtin_icmptypes and obj.name not in self._icmptypes: self.add_icmptype(obj) return ("new", obj) # updated icmptype if path == config.ETC_FIREWALLD_ICMPTYPES: # custom icmptype update if obj.name in self._icmptypes: obj.default = self._icmptypes[obj.name].default self._icmptypes[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_icmptypes: # builtin icmptype update del self._builtin_icmptypes[obj.name] self._builtin_icmptypes[obj.name] = obj if obj.name not in self._icmptypes: # update dbus icmptype return ("update", obj) else: # builtin hidden, no update needed return (None, None) # icmptype not known to firewalld, yet (timeout, ..) return (None, None) def _remove_icmptype(self, obj): if obj.name not in self._icmptypes: raise FirewallError(errors.INVALID_ICMPTYPE, obj.name) if obj.path != config.ETC_FIREWALLD_ICMPTYPES: raise FirewallError(errors.INVALID_DIRECTORY, "'%s' != '%s'" % \ (obj.path, config.ETC_FIREWALLD_ICMPTYPES)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._icmptypes[obj.name] def check_builtin_icmptype(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_ICMPTYPE, "'%s' is built-in icmp type" % obj.name) def remove_icmptype(self, obj): self.check_builtin_icmptype(obj) self._remove_icmptype(obj) def rename_icmptype(self, obj, name): self.check_builtin_icmptype(obj) new_icmptype = self._copy_icmptype(obj, name) self._remove_icmptype(obj) return new_icmptype def _copy_icmptype(self, obj, name): return self.new_icmptype(name, obj.export_config()) # services def get_services(self): return sorted(set(list(self._services.keys()) + \ list(self._builtin_services.keys()))) def add_service(self, obj): if obj.builtin: self._builtin_services[obj.name] = obj else: self._services[obj.name] = obj def get_service(self, name): if name in self._services: return self._services[name] elif name in self._builtin_services: return self._builtin_services[name] raise FirewallError(errors.INVALID_SERVICE, "get_service(): '%s'" % name) def load_service_defaults(self, obj): if obj.name not in self._services: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._services[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._services[%s] != obj" % obj.name) elif obj.name not in self._builtin_services: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in service" % obj.name) self._remove_service(obj) return self._builtin_services[obj.name] def get_service_config(self, obj): conf_dict = obj.export_config_dict() conf_list = [] for i in range(8): # tuple based dbus API has 8 elements if obj.IMPORT_EXPORT_STRUCTURE[i][0] not in conf_dict: # old API needs the empty elements as well. Grab it from the # object otherwise we don't know the type. conf_list.append(copy.deepcopy(getattr(obj, obj.IMPORT_EXPORT_STRUCTURE[i][0]))) else: conf_list.append(conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]]) return tuple(conf_list) def get_service_config_dict(self, obj): return obj.export_config_dict() def set_service_config(self, obj, conf): conf_dict = {} for i,value in enumerate(conf): conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]] = value if obj.builtin: x = copy.copy(obj) x.import_config_dict(conf_dict) x.path = config.ETC_FIREWALLD_SERVICES x.builtin = False if obj.path != x.path: x.default = False self.add_service(x) service_writer(x) return x else: obj.import_config_dict(conf_dict) service_writer(obj) return obj def set_service_config_dict(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.import_config_dict(conf) x.path = config.ETC_FIREWALLD_SERVICES x.builtin = False if obj.path != x.path: x.default = False self.add_service(x) service_writer(x) return x else: obj.import_config_dict(conf) service_writer(obj) return obj def new_service(self, name, conf): if name in self._services or name in self._builtin_services: raise FirewallError(errors.NAME_CONFLICT, "new_service(): '%s'" % name) conf_dict = {} for i,value in enumerate(conf): conf_dict[Service.IMPORT_EXPORT_STRUCTURE[i][0]] = value x = Service() x.check_name(name) x.import_config_dict(conf_dict) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_SERVICES # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True service_writer(x) self.add_service(x) return x def new_service_dict(self, name, conf): if name in self._services or name in self._builtin_services: raise FirewallError(errors.NAME_CONFLICT, "new_service(): '%s'" % name) x = Service() x.check_name(name) x.import_config_dict(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_SERVICES # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True service_writer(x) self.add_service(x) return x def update_service_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path == config.ETC_FIREWALLD_SERVICES: # removed custom service for x in self._services.keys(): obj = self._services[x] if obj.filename == filename: del self._services[x] if obj.name in self._builtin_services: return ("update", self._builtin_services[obj.name]) return ("remove", obj) else: # removed builtin service for x in self._builtin_services.keys(): obj = self._builtin_services[x] if obj.filename == filename: del self._builtin_services[x] if obj.name not in self._services: # update dbus service return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # service not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading service file '%s'", name) try: obj = service_reader(filename, path) except Exception as msg: log.error("Failed to load service file '%s': %s", filename, msg) return (None, None) # new service if obj.name not in self._builtin_services and obj.name not in self._services: self.add_service(obj) return ("new", obj) # updated service if path == config.ETC_FIREWALLD_SERVICES: # custom service update if obj.name in self._services: obj.default = self._services[obj.name].default self._services[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_services: # builtin service update del self._builtin_services[obj.name] self._builtin_services[obj.name] = obj if obj.name not in self._services: # update dbus service return ("update", obj) else: # builtin hidden, no update needed return (None, None) # service not known to firewalld, yet (timeout, ..) return (None, None) def _remove_service(self, obj): if obj.name not in self._services: raise FirewallError(errors.INVALID_SERVICE, obj.name) if obj.path != config.ETC_FIREWALLD_SERVICES: raise FirewallError(errors.INVALID_DIRECTORY, "'%s' != '%s'" % \ (obj.path, config.ETC_FIREWALLD_SERVICES)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._services[obj.name] def check_builtin_service(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_SERVICE, "'%s' is built-in service" % obj.name) def remove_service(self, obj): self.check_builtin_service(obj) self._remove_service(obj) def rename_service(self, obj, name): self.check_builtin_service(obj) new_service = self._copy_service(obj, name) self._remove_service(obj) return new_service def _copy_service(self, obj, name): return self.new_service_dict(name, obj.export_config_dict()) # zones def get_zones(self): return sorted(set(list(self._zones.keys()) + \ list(self._builtin_zones.keys()))) def add_zone(self, obj): if obj.builtin: self._builtin_zones[obj.name] = obj else: self._zones[obj.name] = obj def forget_zone(self, name): if name in self._builtin_zones: del self._builtin_zones[name] if name in self._zones: del self._zones[name] def get_zone(self, name): if name in self._zones: return self._zones[name] elif name in self._builtin_zones: return self._builtin_zones[name] raise FirewallError(errors.INVALID_ZONE, "get_zone(): %s" % name) def load_zone_defaults(self, obj): if obj.name not in self._zones: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._zones[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._zones[%s] != obj" % obj.name) elif obj.name not in self._builtin_zones: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in zone" % obj.name) self._remove_zone(obj) return self._builtin_zones[obj.name] def get_zone_config(self, obj): conf_dict = obj.export_config_dict() conf_list = [] for i in range(16): # tuple based dbus API has 16 elements if obj.IMPORT_EXPORT_STRUCTURE[i][0] not in conf_dict: # old API needs the empty elements as well. Grab it from the # object otherwise we don't know the type. conf_list.append(copy.deepcopy(getattr(obj, obj.IMPORT_EXPORT_STRUCTURE[i][0]))) else: conf_list.append(conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]]) return tuple(conf_list) def get_zone_config_dict(self, obj): return obj.export_config_dict() def set_zone_config(self, obj, conf): conf_dict = {} for i,value in enumerate(conf): conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]] = value if obj.builtin: x = copy.copy(obj) x.fw_config = self x.import_config_dict(conf_dict) x.path = config.ETC_FIREWALLD_ZONES x.builtin = False if obj.path != x.path: x.default = False self.add_zone(x) zone_writer(x) return x else: obj.fw_config = self obj.import_config_dict(conf_dict) zone_writer(obj) return obj def set_zone_config_dict(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.fw_config = self x.import_config_dict(conf) x.path = config.ETC_FIREWALLD_ZONES x.builtin = False if obj.path != x.path: x.default = False self.add_zone(x) zone_writer(x) return x else: obj.fw_config = self obj.import_config_dict(conf) zone_writer(obj) return obj def new_zone(self, name, conf): if name in self._zones or name in self._builtin_zones: raise FirewallError(errors.NAME_CONFLICT, "new_zone(): '%s'" % name) conf_dict = {} for i,value in enumerate(conf): conf_dict[Zone.IMPORT_EXPORT_STRUCTURE[i][0]] = value x = Zone() x.fw_config = self x.check_name(name) x.import_config_dict(conf_dict) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_ZONES # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True zone_writer(x) self.add_zone(x) return x def new_zone_dict(self, name, conf): if name in self._zones or name in self._builtin_zones: raise FirewallError(errors.NAME_CONFLICT, "new_zone(): '%s'" % name) x = Zone() x.fw_config = self x.check_name(name) x.import_config_dict(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_ZONES # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True zone_writer(x) self.add_zone(x) return x def update_zone_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path.startswith(config.ETC_FIREWALLD_ZONES): # removed custom zone for x in self._zones.keys(): obj = self._zones[x] if obj.filename == filename: del self._zones[x] if obj.name in self._builtin_zones: return ("update", self._builtin_zones[obj.name]) return ("remove", obj) else: # removed builtin zone for x in self._builtin_zones.keys(): obj = self._builtin_zones[x] if obj.filename == filename: del self._builtin_zones[x] if obj.name not in self._zones: # update dbus zone return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # zone not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading zone file '%s'", name) try: obj = zone_reader(filename, path) except Exception as msg: log.error("Failed to load zone file '%s': %s", filename, msg) return (None, None) obj.fw_config = self if path.startswith(config.ETC_FIREWALLD_ZONES) and \ len(path) > len(config.ETC_FIREWALLD_ZONES): # custom combined zone part obj.name = "%s/%s" % (os.path.basename(path), os.path.basename(filename)[0:-4]) # new zone if obj.name not in self._builtin_zones and obj.name not in self._zones: self.add_zone(obj) return ("new", obj) # updated zone if path.startswith(config.ETC_FIREWALLD_ZONES): # custom zone update if obj.name in self._zones: obj.default = self._zones[obj.name].default self._zones[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_zones: # builtin zone update del self._builtin_zones[obj.name] self._builtin_zones[obj.name] = obj if obj.name not in self._zones: # update dbus zone return ("update", obj) else: # builtin hidden, no update needed return (None, None) # zone not known to firewalld, yet (timeout, ..) return (None, None) def _remove_zone(self, obj): if obj.name not in self._zones: raise FirewallError(errors.INVALID_ZONE, obj.name) if not obj.path.startswith(config.ETC_FIREWALLD_ZONES): raise FirewallError(errors.INVALID_DIRECTORY, "'%s' doesn't start with '%s'" % \ (obj.path, config.ETC_FIREWALLD_ZONES)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._zones[obj.name] def check_builtin_zone(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_ZONE, "'%s' is built-in zone" % obj.name) def remove_zone(self, obj): self.check_builtin_zone(obj) self._remove_zone(obj) def rename_zone(self, obj, name): self.check_builtin_zone(obj) obj_conf = obj.export_config_dict() self._remove_zone(obj) try: new_zone = self.new_zone_dict(name, obj_conf) except: # re-add original if rename failed self.new_zone_dict(obj.name, obj_conf) raise return new_zone # policy objects def get_policy_objects(self): return sorted(set(list(self._policy_objects.keys()) + \ list(self._builtin_policy_objects.keys()))) def add_policy_object(self, obj): if obj.builtin: self._builtin_policy_objects[obj.name] = obj else: self._policy_objects[obj.name] = obj def get_policy_object(self, name): if name in self._policy_objects: return self._policy_objects[name] elif name in self._builtin_policy_objects: return self._builtin_policy_objects[name] raise FirewallError(errors.INVALID_POLICY, "get_policy_object(): %s" % name) def load_policy_object_defaults(self, obj): if obj.name not in self._policy_objects: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._policy_objects[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._policy_objects[%s] != obj" % obj.name) elif obj.name not in self._builtin_policy_objects: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in policy" % obj.name) self._remove_policy_object(obj) return self._builtin_policy_objects[obj.name] def get_policy_object_config_dict(self, obj): return obj.export_config_dict() def set_policy_object_config_dict(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.fw_config = self x.import_config_dict(conf) x.path = config.ETC_FIREWALLD_POLICIES x.builtin = False if obj.path != x.path: x.default = False self.add_policy_object(x) policy_writer(x) return x else: obj.fw_config = self obj.import_config_dict(conf) policy_writer(obj) return obj def new_policy_object_dict(self, name, conf): if name in self._policy_objects or name in self._builtin_policy_objects: raise FirewallError(errors.NAME_CONFLICT, "new_policy_object(): '%s'" % name) x = Policy() x.fw_config = self x.check_name(name) x.import_config_dict(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_POLICIES # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True policy_writer(x) self.add_policy_object(x) return x def update_policy_object_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path.startswith(config.ETC_FIREWALLD_POLICIES): # removed custom policy_object for x in self._policy_objects.keys(): obj = self._policy_objects[x] if obj.filename == filename: del self._policy_objects[x] if obj.name in self._builtin_policy_objects: return ("update", self._builtin_policy_objects[obj.name]) return ("remove", obj) else: # removed builtin policy_object for x in self._builtin_policy_objects.keys(): obj = self._builtin_policy_objects[x] if obj.filename == filename: del self._builtin_policy_objects[x] if obj.name not in self._policy_objects: # update dbus policy_object return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # policy_object not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading policy file '%s'", name) try: obj = policy_reader(filename, path) except Exception as msg: log.error("Failed to load policy file '%s': %s", filename, msg) return (None, None) obj.fw_config = self if path.startswith(config.ETC_FIREWALLD_POLICIES) and \ len(path) > len(config.ETC_FIREWALLD_POLICIES): # custom combined policy_object part obj.name = "%s/%s" % (os.path.basename(path), os.path.basename(filename)[0:-4]) # new policy_object if obj.name not in self._builtin_policy_objects and obj.name not in self._policy_objects: self.add_policy_object(obj) return ("new", obj) # updated policy_object if path.startswith(config.ETC_FIREWALLD_POLICIES): # custom policy_object update if obj.name in self._policy_objects: obj.default = self._policy_objects[obj.name].default self._policy_objects[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_policy_objects: # builtin policy_object update del self._builtin_policy_objects[obj.name] self._builtin_policy_objects[obj.name] = obj if obj.name not in self._policy_objects: # update dbus policy_object return ("update", obj) else: # builtin hidden, no update needed return (None, None) # policy_object not known to firewalld, yet (timeout, ..) return (None, None) def _remove_policy_object(self, obj): if obj.name not in self._policy_objects: raise FirewallError(errors.INVALID_POLICY, obj.name) if not obj.path.startswith(config.ETC_FIREWALLD_POLICIES): raise FirewallError(errors.INVALID_DIRECTORY, "'%s' doesn't start with '%s'" % \ (obj.path, config.ETC_FIREWALLD_POLICIES)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._policy_objects[obj.name] def check_builtin_policy_object(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_POLICY, "'%s' is built-in policy" % obj.name) def remove_policy_object(self, obj): self.check_builtin_policy_object(obj) self._remove_policy_object(obj) def rename_policy_object(self, obj, name): self.check_builtin_policy_object(obj) new_policy_object = self._copy_policy_object(obj, name) self._remove_policy_object(obj) return new_policy_object def _copy_policy_object(self, obj, name): return self.new_policy_object_dict(name, obj.export_config_dict()) # helper def get_helpers(self): return sorted(set(list(self._helpers.keys()) + \ list(self._builtin_helpers.keys()))) def add_helper(self, obj): if obj.builtin: self._builtin_helpers[obj.name] = obj else: self._helpers[obj.name] = obj def get_helper(self, name): if name in self._helpers: return self._helpers[name] elif name in self._builtin_helpers: return self._builtin_helpers[name] raise FirewallError(errors.INVALID_HELPER, name) def load_helper_defaults(self, obj): if obj.name not in self._helpers: raise FirewallError(errors.NO_DEFAULTS, obj.name) elif self._helpers[obj.name] != obj: raise FirewallError(errors.NO_DEFAULTS, "self._helpers[%s] != obj" % obj.name) elif obj.name not in self._builtin_helpers: raise FirewallError(errors.NO_DEFAULTS, "'%s' not a built-in helper" % obj.name) self._remove_helper(obj) return self._builtin_helpers[obj.name] def get_helper_config(self, obj): return obj.export_config() def set_helper_config(self, obj, conf): if obj.builtin: x = copy.copy(obj) x.import_config(conf) x.path = config.ETC_FIREWALLD_HELPERS x.builtin = False if obj.path != x.path: x.default = False self.add_helper(x) helper_writer(x) return x else: obj.import_config(conf) helper_writer(obj) return obj def new_helper(self, name, conf): if name in self._helpers or name in self._builtin_helpers: raise FirewallError(errors.NAME_CONFLICT, "new_helper(): '%s'" % name) x = Helper() x.check_name(name) x.import_config(conf) x.name = name x.filename = "%s.xml" % name x.path = config.ETC_FIREWALLD_HELPERS # It is not possible to add a new one with a name of a buitin x.builtin = False x.default = True helper_writer(x) self.add_helper(x) return x def update_helper_from_path(self, name): filename = os.path.basename(name) path = os.path.dirname(name) if not os.path.exists(name): # removed file if path == config.ETC_FIREWALLD_HELPERS: # removed custom helper for x in self._helpers.keys(): obj = self._helpers[x] if obj.filename == filename: del self._helpers[x] if obj.name in self._builtin_helpers: return ("update", self._builtin_helpers[obj.name]) return ("remove", obj) else: # removed builtin helper for x in self._builtin_helpers.keys(): obj = self._builtin_helpers[x] if obj.filename == filename: del self._builtin_helpers[x] if obj.name not in self._helpers: # update dbus helper return ("remove", obj) else: # builtin hidden, no update needed return (None, None) # helper not known to firewalld, yet (timeout, ..) return (None, None) # new or updated file log.debug1("Loading helper file '%s'", name) try: obj = helper_reader(filename, path) except Exception as msg: log.error("Failed to load helper file '%s': %s", filename, msg) return (None, None) # new helper if obj.name not in self._builtin_helpers and obj.name not in self._helpers: self.add_helper(obj) return ("new", obj) # updated helper if path == config.ETC_FIREWALLD_HELPERS: # custom helper update if obj.name in self._helpers: obj.default = self._helpers[obj.name].default self._helpers[obj.name] = obj return ("update", obj) else: if obj.name in self._builtin_helpers: # builtin helper update del self._builtin_helpers[obj.name] self._builtin_helpers[obj.name] = obj if obj.name not in self._helpers: # update dbus helper return ("update", obj) else: # builtin hidden, no update needed return (None, None) # helper not known to firewalld, yet (timeout, ..) return (None, None) def _remove_helper(self, obj): if obj.name not in self._helpers: raise FirewallError(errors.INVALID_HELPER, obj.name) if obj.path != config.ETC_FIREWALLD_HELPERS: raise FirewallError(errors.INVALID_DIRECTORY, "'%s' != '%s'" % (obj.path, config.ETC_FIREWALLD_HELPERS)) name = "%s/%s.xml" % (obj.path, obj.name) try: shutil.move(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) os.remove(name) del self._helpers[obj.name] def check_builtin_helper(self, obj): if obj.builtin or not obj.default: raise FirewallError(errors.BUILTIN_HELPER, "'%s' is built-in helper" % obj.name) def remove_helper(self, obj): self.check_builtin_helper(obj) self._remove_helper(obj) def rename_helper(self, obj, name): self.check_builtin_helper(obj) new_helper = self._copy_helper(obj, name) self._remove_helper(obj) return new_helper def _copy_helper(self, obj, name): return self.new_helper(name, obj.export_config()) PKpge[vg=V=V fw_policy.pynu[# -*- coding: utf-8 -*- # # SPDX-License-Identifier: GPL-2.0-or-later import time import copy from firewall.core.logger import log from firewall.functions import portStr, checkIPnMask, checkIP6nMask, \ checkProtocol, enable_ip_forwarding, check_single_address, \ portInPortRange, get_nf_conntrack_short_name, coalescePortRange, breakPortRange from firewall.core.rich import Rich_Rule, Rich_Accept, \ Rich_Service, Rich_Port, Rich_Protocol, \ Rich_Masquerade, Rich_ForwardPort, Rich_SourcePort, Rich_IcmpBlock, \ Rich_IcmpType, Rich_Mark from firewall.core.fw_transaction import FirewallTransaction from firewall import errors from firewall.errors import FirewallError from firewall.fw_types import LastUpdatedOrderedDict from firewall.core.base import SOURCE_IPSET_TYPES class FirewallPolicy(object): def __init__(self, fw): self._fw = fw self._chains = { } self._policies = { } def __repr__(self): return '%s(%r, %r)' % (self.__class__, self._chains, self._policies) def cleanup(self): self._chains.clear() self._policies.clear() # transaction def new_transaction(self): return FirewallTransaction(self._fw) # policies def get_policies(self): return sorted(self._policies.keys()) def get_policies_not_derived_from_zone(self): policies = [] for p in self.get_policies(): p_obj = self.get_policy(p) if not p_obj.derived_from_zone: policies.append(p) return sorted(policies) def get_active_policies_not_derived_from_zone(self): active_policies = [] for policy in self.get_policies_not_derived_from_zone(): settings = self.get_settings(policy) if (set(settings["ingress_zones"]) & (set(self._fw.zone.get_active_zones()) | set(["HOST", "ANY"]))) and \ (set(settings["egress_zones"]) & (set(self._fw.zone.get_active_zones()) | set(["HOST", "ANY"]))): active_policies.append(policy) return active_policies def get_policy(self, policy): p = self._fw.check_policy(policy) return self._policies[p] def add_policy(self, obj): obj.settings = { x : LastUpdatedOrderedDict() for x in [ "services", "ports", "masquerade", "forward_ports", "source_ports", "icmp_blocks", "rules", "protocols", "icmp_block_inversion", "ingress_zones", "egress_zones" ] } self._policies[obj.name] = obj self.copy_permanent_to_runtime(obj.name) def remove_policy(self, policy): obj = self._policies[policy] if obj.applied: self.unapply_policy_settings(policy) obj.settings.clear() del self._policies[policy] def copy_permanent_to_runtime(self, policy): obj = self._policies[policy] if obj.applied: return for args in obj.ingress_zones: self.add_ingress_zone(policy, args, allow_apply=False) for args in obj.egress_zones: self.add_egress_zone(policy, args, allow_apply=False) for args in obj.icmp_blocks: self.add_icmp_block(policy, args) for args in obj.forward_ports: self.add_forward_port(policy, *args) for args in obj.services: self.add_service(policy, args) for args in obj.ports: try: self.add_port(policy, *args) except FirewallError as error: if error.code in [errors.ALREADY_ENABLED]: log.warning(error) else: raise error for args in obj.protocols: self.add_protocol(policy, args) for args in obj.source_ports: try: self.add_source_port(policy, *args) except FirewallError as error: if error.code in [errors.ALREADY_ENABLED]: log.warning(error) else: raise error for args in obj.rules: self.add_rule(policy, args) if obj.masquerade: self.add_masquerade(policy) def apply_policies(self, use_transaction=None): for policy in self.get_policies(): p_obj = self._policies[policy] if p_obj.derived_from_zone: continue if policy in self.get_active_policies_not_derived_from_zone(): log.debug1("Applying policy '%s'", policy) self.apply_policy_settings(policy, use_transaction=use_transaction) def set_policy_applied(self, policy, applied): obj = self._policies[policy] obj.applied = applied # settings # generate settings record with sender, timeout def __gen_settings(self, timeout, sender): ret = { "date": time.time(), "sender": sender, "timeout": timeout, } return ret def get_settings(self, policy): return self.get_policy(policy).settings def _policy_settings(self, enable, policy, use_transaction=None): _policy = self._fw.check_policy(policy) obj = self._policies[_policy] if (enable and obj.applied) or (not enable and not obj.applied): return if enable: obj.applied = True if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if enable: # build the base chain layout of the policy for (table, chain) in self._get_table_chains_for_policy_dispatch(policy) if not obj.derived_from_zone \ else self._get_table_chains_for_zone_dispatch(policy): self.gen_chain_rules(policy, True, table, chain, transaction) settings = self.get_settings(policy) if not obj.derived_from_zone: self._ingress_egress_zones(enable, _policy, transaction) for key in settings: for args in settings[key]: if key == "icmp_blocks": self._icmp_block(enable, _policy, args, transaction) elif key == "icmp_block_inversion": continue elif key == "forward_ports": self._forward_port(enable, _policy, transaction, *args) elif key == "services": self._service(enable, _policy, args, transaction) elif key == "ports": self._port(enable, _policy, args[0], args[1], transaction) elif key == "protocols": self._protocol(enable, _policy, args, transaction) elif key == "source_ports": self._source_port(enable, _policy, args[0], args[1], transaction) elif key == "masquerade": self._masquerade(enable, _policy, transaction) elif key == "rules": self.__rule(enable, _policy, Rich_Rule(rule_str=args), transaction) elif key == "ingress_zones": continue elif key == "egress_zones": continue else: log.warning("Policy '%s': Unknown setting '%s:%s', " "unable to apply", policy, key, args) if not enable: for (table, chain) in self._get_table_chains_for_policy_dispatch(policy) if not obj.derived_from_zone \ else self._get_table_chains_for_zone_dispatch(policy): self.gen_chain_rules(policy, False, table, chain, transaction) obj.applied = False if use_transaction is None: transaction.execute(enable) def apply_policy_settings(self, policy, use_transaction=None): self._policy_settings(True, policy, use_transaction=use_transaction) def unapply_policy_settings(self, policy, use_transaction=None): self._policy_settings(False, policy, use_transaction=use_transaction) def get_config_with_settings_dict(self, policy): """ :return: exported config updated with runtime settings """ permanent = self.get_policy(policy).export_config_dict() runtime = { "services": self.list_services(policy), "ports": self.list_ports(policy), "icmp_blocks": self.list_icmp_blocks(policy), "masquerade": self.query_masquerade(policy), "forward_ports": self.list_forward_ports(policy), "rich_rules": self.list_rules(policy), "protocols": self.list_protocols(policy), "source_ports": self.list_source_ports(policy), "ingress_zones": self.list_ingress_zones(policy), "egress_zones": self.list_egress_zones(policy), } return self._fw.combine_runtime_with_permanent_settings(permanent, runtime) def set_config_with_settings_dict(self, policy, settings, sender): # stupid wrappers to convert rich rule string to rich rule object from firewall.core.rich import Rich_Rule def add_rule_wrapper(policy, rule_str, timeout=0, sender=None): self.add_rule(policy, Rich_Rule(rule_str=rule_str), timeout=0, sender=sender) def remove_rule_wrapper(policy, rule_str): self.remove_rule(policy, Rich_Rule(rule_str=rule_str)) setting_to_fn = { "services": (self.add_service, self.remove_service), "ports": (self.add_port, self.remove_port), "icmp_blocks": (self.add_icmp_block, self.remove_icmp_block), "masquerade": (self.add_masquerade, self.remove_masquerade), "forward_ports": (self.add_forward_port, self.remove_forward_port), "rich_rules": (add_rule_wrapper, remove_rule_wrapper), "protocols": (self.add_protocol, self.remove_protocol), "source_ports": (self.add_source_port, self.remove_source_port), "ingress_zones": (self.add_ingress_zone, self.remove_ingress_zone), "egress_zones": (self.add_egress_zone, self.remove_egress_zone), } old_settings = self.get_config_with_settings_dict(policy) (add_settings, remove_settings) = self._fw.get_added_and_removed_settings(old_settings, settings) for key in remove_settings: if isinstance(remove_settings[key], list): for args in remove_settings[key]: if isinstance(args, tuple): setting_to_fn[key][1](policy, *args) else: setting_to_fn[key][1](policy, args) else: # bool setting_to_fn[key][1](policy) for key in add_settings: if isinstance(add_settings[key], list): for args in add_settings[key]: if isinstance(args, tuple): setting_to_fn[key][0](policy, *args, timeout=0, sender=sender) else: setting_to_fn[key][0](policy, args, timeout=0, sender=sender) else: # bool setting_to_fn[key][0](policy, timeout=0, sender=sender) # ingress zones def check_ingress_zone(self, zone): if not zone: raise FirewallError(errors.INVALID_ZONE) if zone not in ["HOST", "ANY"]: self._fw.check_zone(zone) def __ingress_zone_id(self, zone): self.check_ingress_zone(zone) return zone def add_ingress_zone(self, policy, zone, timeout=0, sender=None, use_transaction=None, allow_apply=True): _policy = self._fw.check_policy(policy) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._policies[_policy] zone_id = self.__ingress_zone_id(zone) if zone_id in _obj.settings["ingress_zones"]: raise FirewallError(errors.ALREADY_ENABLED, "'%s' already in '%s'" % (zone, _policy)) if "ANY" in _obj.settings["ingress_zones"] or "HOST" in _obj.settings["ingress_zones"] or \ zone in ["ANY", "HOST"] and _obj.settings["ingress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'ingress-zones' may only contain one of: many regular zones, ANY, or HOST") if zone == "HOST" and "HOST" in _obj.settings["egress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'HOST' can only appear in either ingress or egress zones, but not both") if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if allow_apply: if _obj.applied: self._ingress_egress_zones(False, _policy, transaction) # register early so backends can access updated zone list self.__register_ingress_zone(_obj, zone_id, timeout, sender) transaction.add_fail(self.__unregister_ingress_zone, _obj, zone_id) if not _obj.applied: if _policy in self.get_active_policies_not_derived_from_zone(): self.apply_policy_settings(_policy, use_transaction=transaction) transaction.add_fail(self.set_policy_applied, _policy, False) else: self._ingress_egress_zones(True, _policy, transaction) else: self.__register_ingress_zone(_obj, zone_id, timeout, sender) transaction.add_fail(self.__unregister_ingress_zone, _obj, zone_id) if use_transaction is None: transaction.execute(True) def __register_ingress_zone(self, _obj, zone_id, timeout, sender): _obj.settings["ingress_zones"][zone_id] = self.__gen_settings(timeout, sender) def remove_ingress_zone(self, policy, zone, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] zone_id = self.__ingress_zone_id(zone) if zone_id not in _obj.settings["ingress_zones"]: raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (zone, _policy)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: if len(_obj.settings["ingress_zones"]) == 1: self.unapply_policy_settings(_policy, transaction) else: self._ingress_egress_zones(False, _policy, transaction) # unregister early so backends have updated zone list self.__unregister_ingress_zone(_obj, zone_id) transaction.add_fail(self.__register_ingress_zone, _obj, zone_id, None, None) if _policy in self.get_active_policies_not_derived_from_zone(): self._ingress_egress_zones(True, _policy, transaction) else: transaction.add_post(self.__unregister_ingress_zone, _obj, zone_id) if use_transaction is None: transaction.execute(True) return _policy def __unregister_ingress_zone(self, _obj, zone_id): if zone_id in _obj.settings["ingress_zones"]: del _obj.settings["ingress_zones"][zone_id] def query_ingress_zone(self, policy, zone): return self.__ingress_zone_id(zone) in self.get_settings(policy)["ingress_zones"] def list_ingress_zones(self, policy): return list(self.get_settings(policy)["ingress_zones"].keys()) # egress zones def check_egress_zone(self, zone): if not zone: raise FirewallError(errors.INVALID_ZONE) if zone not in ["HOST", "ANY"]: self._fw.check_zone(zone) def __egress_zone_id(self, zone): self.check_egress_zone(zone) return zone def add_egress_zone(self, policy, zone, timeout=0, sender=None, use_transaction=None, allow_apply=True): _policy = self._fw.check_policy(policy) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._policies[_policy] zone_id = self.__egress_zone_id(zone) if zone_id in _obj.settings["egress_zones"]: raise FirewallError(errors.ALREADY_ENABLED, "'%s' already in '%s'" % (zone, _policy)) if "ANY" in _obj.settings["egress_zones"] or "HOST" in _obj.settings["egress_zones"] or \ zone in ["ANY", "HOST"] and _obj.settings["egress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'egress-zones' may only contain one of: many regular zones, ANY, or HOST") if zone == "HOST" and "HOST" in _obj.settings["ingress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'HOST' can only appear in either ingress or egress zones, but not both") if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if allow_apply: if _obj.applied: self._ingress_egress_zones(False, _policy, transaction) # register early so backends can access updated zone list self.__register_egress_zone(_obj, zone_id, timeout, sender) transaction.add_fail(self.__unregister_egress_zone, _obj, zone_id) if not _obj.applied: if _policy in self.get_active_policies_not_derived_from_zone(): self.apply_policy_settings(_policy, use_transaction=transaction) transaction.add_fail(self.set_policy_applied, _policy, False) else: self._ingress_egress_zones(True, _policy, transaction) else: self.__register_egress_zone(_obj, zone_id, timeout, sender) transaction.add_fail(self.__unregister_egress_zone, _obj, zone_id) if use_transaction is None: transaction.execute(True) def __register_egress_zone(self, _obj, zone_id, timeout, sender): _obj.settings["egress_zones"][zone_id] = self.__gen_settings(timeout, sender) def remove_egress_zone(self, policy, zone, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] zone_id = self.__egress_zone_id(zone) if zone_id not in _obj.settings["egress_zones"]: raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (zone, _policy)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: if len(_obj.settings["egress_zones"]) == 1: self.unapply_policy_settings(_policy, transaction) else: self._ingress_egress_zones(False, _policy, transaction) # unregister early so backends have updated zone list self.__unregister_egress_zone(_obj, zone_id) transaction.add_fail(self.__register_egress_zone, _obj, zone_id, None, None) if _policy in self.get_active_policies_not_derived_from_zone(): self._ingress_egress_zones(True, _policy, transaction) else: transaction.add_post(self.__unregister_egress_zone, _obj, zone_id) if use_transaction is None: transaction.execute(True) return _policy def __unregister_egress_zone(self, _obj, zone_id): if zone_id in _obj.settings["egress_zones"]: del _obj.settings["egress_zones"][zone_id] def query_egress_zone(self, policy, zone): return self.__egress_zone_id(zone) in self.get_settings(policy)["egress_zones"] def list_egress_zones(self, policy): return list(self.get_settings(policy)["egress_zones"].keys()) # RICH LANGUAGE def check_rule(self, rule): rule.check() def __rule_id(self, rule): self.check_rule(rule) return str(rule) def _rule_source_ipv(self, source): if not source: return None if source.addr: if checkIPnMask(source.addr): return "ipv4" elif checkIP6nMask(source.addr): return "ipv6" elif hasattr(source, "mac") and source.mac: return "" elif hasattr(source, "ipset") and source.ipset: self._check_ipset_type_for_source(source.ipset) self._check_ipset_applied(source.ipset) return self._ipset_family(source.ipset) return None def __rule(self, enable, policy, rule, transaction): self._rule_prepare(enable, policy, rule, transaction) def add_rule(self, policy, rule, timeout=0, sender=None, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._policies[_policy] rule_id = self.__rule_id(rule) if rule_id in _obj.settings["rules"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.ALREADY_ENABLED, "'%s' already in '%s'" % (rule, _name)) if not _obj.derived_from_zone: if rule.element and isinstance(rule.element, Rich_Masquerade): if "HOST" in _obj.settings["egress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for egress zone 'HOST'") if "HOST" in _obj.settings["ingress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for ingress zone 'HOST'") for zone in _obj.settings["ingress_zones"]: if zone == "ANY": continue if self._fw.zone.list_interfaces(zone): raise FirewallError(errors.INVALID_ZONE, "'masquerade' cannot be used in a policy if an ingress zone has assigned interfaces") if rule.element and isinstance(rule.element, Rich_ForwardPort): if "HOST" in _obj.settings["egress_zones"]: if rule.element.to_address: raise FirewallError(errors.INVALID_FORWARD, "A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'") elif _obj.settings["egress_zones"]: if not rule.element.to_address: raise FirewallError(errors.INVALID_FORWARD, "'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone") for zone in _obj.settings["egress_zones"]: if zone == "ANY": continue if self._fw.zone.list_interfaces(zone): raise FirewallError(errors.INVALID_ZONE, "'forward-port' cannot be used in a policy if an egress zone has assigned interfaces") if rule.action and isinstance(rule.action, Rich_Mark): for zone in _obj.settings["egress_zones"]: if zone in ["ANY", "HOST"]: continue if self._fw.zone.list_interfaces(zone): raise FirewallError(errors.INVALID_ZONE, "'mark' action cannot be used in a policy if an egress zone has assigned interfaces") if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self.__rule(True, _policy, rule, transaction) self.__register_rule(_obj, rule_id, timeout, sender) transaction.add_fail(self.__unregister_rule, _obj, rule_id) if use_transaction is None: transaction.execute(True) return _policy def __register_rule(self, _obj, rule_id, timeout, sender): _obj.settings["rules"][rule_id] = self.__gen_settings( timeout, sender) def remove_rule(self, policy, rule, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] rule_id = self.__rule_id(rule) if rule_id not in _obj.settings["rules"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (rule, _name)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self.__rule(False, _policy, rule, transaction) transaction.add_post(self.__unregister_rule, _obj, rule_id) if use_transaction is None: transaction.execute(True) return _policy def __unregister_rule(self, _obj, rule_id): if rule_id in _obj.settings["rules"]: del _obj.settings["rules"][rule_id] def query_rule(self, policy, rule): return self.__rule_id(rule) in self.get_settings(policy)["rules"] def list_rules(self, policy): return list(self.get_settings(policy)["rules"].keys()) # SERVICES def check_service(self, service): self._fw.check_service(service) def __service_id(self, service): self.check_service(service) return service def add_service(self, policy, service, timeout=0, sender=None, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._policies[_policy] service_id = self.__service_id(service) if service_id in _obj.settings["services"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.ALREADY_ENABLED, "'%s' already in '%s'" % (service, _name)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._service(True, _policy, service, transaction) self.__register_service(_obj, service_id, timeout, sender) transaction.add_fail(self.__unregister_service, _obj, service_id) if use_transaction is None: transaction.execute(True) return _policy def __register_service(self, _obj, service_id, timeout, sender): _obj.settings["services"][service_id] = \ self.__gen_settings(timeout, sender) def remove_service(self, policy, service, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] service_id = self.__service_id(service) if service_id not in _obj.settings["services"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (service, _name)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._service(False, _policy, service, transaction) transaction.add_post(self.__unregister_service, _obj, service_id) if use_transaction is None: transaction.execute(True) return _policy def __unregister_service(self, _obj, service_id): if service_id in _obj.settings["services"]: del _obj.settings["services"][service_id] def query_service(self, policy, service): return self.__service_id(service) in self.get_settings(policy)["services"] def list_services(self, policy): return self.get_settings(policy)["services"].keys() def get_helpers_for_service_helpers(self, helpers): _helpers = [ ] for helper in helpers: try: _helper = self._fw.helper.get_helper(helper) except FirewallError: raise FirewallError(errors.INVALID_HELPER, helper) _helpers.append(_helper) return _helpers def get_helpers_for_service_modules(self, modules, enable): # If automatic helper assignment is turned off, helpers that # do not have ports defined will be replaced by the helpers # that the helper.module defines. _helpers = [ ] for module in modules: try: helper = self._fw.helper.get_helper(module) except FirewallError: raise FirewallError(errors.INVALID_HELPER, module) if len(helper.ports) < 1: _module_short_name = get_nf_conntrack_short_name(helper.module) try: _helper = self._fw.helper.get_helper(_module_short_name) _helpers.append(_helper) except FirewallError: if enable: log.warning("Helper '%s' is not available" % _module_short_name) continue else: _helpers.append(helper) return _helpers # PORTS def check_port(self, port, protocol): self._fw.check_port(port) self._fw.check_tcpudp(protocol) def __port_id(self, port, protocol): self.check_port(port, protocol) return (portStr(port, "-"), protocol) def add_port(self, policy, port, protocol, timeout=0, sender=None, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._policies[_policy] existing_port_ids = list(filter(lambda x: x[1] == protocol, _obj.settings["ports"])) for port_id in existing_port_ids: if portInPortRange(port, port_id[0]): _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.ALREADY_ENABLED, "'%s:%s' already in '%s'" % (port, protocol, _name)) added_ranges, removed_ranges = coalescePortRange(port, [_port for (_port, _protocol) in existing_port_ids]) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: for range in added_ranges: self._port(True, _policy, portStr(range, "-"), protocol, transaction) for range in removed_ranges: self._port(False, _policy, portStr(range, "-"), protocol, transaction) for range in added_ranges: port_id = self.__port_id(range, protocol) self.__register_port(_obj, port_id, timeout, sender) transaction.add_fail(self.__unregister_port, _obj, port_id) for range in removed_ranges: port_id = self.__port_id(range, protocol) transaction.add_post(self.__unregister_port, _obj, port_id) if use_transaction is None: transaction.execute(True) return _policy def __register_port(self, _obj, port_id, timeout, sender): _obj.settings["ports"][port_id] = \ self.__gen_settings(timeout, sender) def remove_port(self, policy, port, protocol, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] existing_port_ids = list(filter(lambda x: x[1] == protocol, _obj.settings["ports"])) for port_id in existing_port_ids: if portInPortRange(port, port_id[0]): break else: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.NOT_ENABLED, "'%s:%s' not in '%s'" % (port, protocol, _name)) added_ranges, removed_ranges = breakPortRange(port, [_port for (_port, _protocol) in existing_port_ids]) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: for range in added_ranges: self._port(True, _policy, portStr(range, "-"), protocol, transaction) for range in removed_ranges: self._port(False, _policy, portStr(range, "-"), protocol, transaction) for range in added_ranges: port_id = self.__port_id(range, protocol) self.__register_port(_obj, port_id, 0, None) transaction.add_fail(self.__unregister_port, _obj, port_id) for range in removed_ranges: port_id = self.__port_id(range, protocol) transaction.add_post(self.__unregister_port, _obj, port_id) if use_transaction is None: transaction.execute(True) return _policy def __unregister_port(self, _obj, port_id): if port_id in _obj.settings["ports"]: del _obj.settings["ports"][port_id] def query_port(self, policy, port, protocol): for (_port, _protocol) in self.get_settings(policy)["ports"]: if portInPortRange(port, _port) and protocol == _protocol: return True return False def list_ports(self, policy): return list(self.get_settings(policy)["ports"].keys()) # PROTOCOLS def check_protocol(self, protocol): if not checkProtocol(protocol): raise FirewallError(errors.INVALID_PROTOCOL, protocol) def __protocol_id(self, protocol): self.check_protocol(protocol) return protocol def add_protocol(self, policy, protocol, timeout=0, sender=None, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._policies[_policy] protocol_id = self.__protocol_id(protocol) if protocol_id in _obj.settings["protocols"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.ALREADY_ENABLED, "'%s' already in '%s'" % (protocol, _name)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._protocol(True, _policy, protocol, transaction) self.__register_protocol(_obj, protocol_id, timeout, sender) transaction.add_fail(self.__unregister_protocol, _obj, protocol_id) if use_transaction is None: transaction.execute(True) return _policy def __register_protocol(self, _obj, protocol_id, timeout, sender): _obj.settings["protocols"][protocol_id] = \ self.__gen_settings(timeout, sender) def remove_protocol(self, policy, protocol, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] protocol_id = self.__protocol_id(protocol) if protocol_id not in _obj.settings["protocols"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (protocol, _name)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._protocol(False, _policy, protocol, transaction) transaction.add_post(self.__unregister_protocol, _obj, protocol_id) if use_transaction is None: transaction.execute(True) return _policy def __unregister_protocol(self, _obj, protocol_id): if protocol_id in _obj.settings["protocols"]: del _obj.settings["protocols"][protocol_id] def query_protocol(self, policy, protocol): return self.__protocol_id(protocol) in self.get_settings(policy)["protocols"] def list_protocols(self, policy): return list(self.get_settings(policy)["protocols"].keys()) # SOURCE PORTS def __source_port_id(self, port, protocol): self.check_port(port, protocol) return (portStr(port, "-"), protocol) def add_source_port(self, policy, port, protocol, timeout=0, sender=None, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._policies[_policy] existing_port_ids = list(filter(lambda x: x[1] == protocol, _obj.settings["source_ports"])) for port_id in existing_port_ids: if portInPortRange(port, port_id[0]): _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.ALREADY_ENABLED, "'%s:%s' already in '%s'" % (port, protocol, _name)) added_ranges, removed_ranges = coalescePortRange(port, [_port for (_port, _protocol) in existing_port_ids]) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: for range in added_ranges: self._source_port(True, _policy, portStr(range, "-"), protocol, transaction) for range in removed_ranges: self._source_port(False, _policy, portStr(range, "-"), protocol, transaction) for range in added_ranges: port_id = self.__source_port_id(range, protocol) self.__register_source_port(_obj, port_id, timeout, sender) transaction.add_fail(self.__unregister_source_port, _obj, port_id) for range in removed_ranges: port_id = self.__source_port_id(range, protocol) transaction.add_post(self.__unregister_source_port, _obj, port_id) if use_transaction is None: transaction.execute(True) return _policy def __register_source_port(self, _obj, port_id, timeout, sender): _obj.settings["source_ports"][port_id] = \ self.__gen_settings(timeout, sender) def remove_source_port(self, policy, port, protocol, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] existing_port_ids = list(filter(lambda x: x[1] == protocol, _obj.settings["source_ports"])) for port_id in existing_port_ids: if portInPortRange(port, port_id[0]): break else: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.NOT_ENABLED, "'%s:%s' not in '%s'" % (port, protocol, _name)) added_ranges, removed_ranges = breakPortRange(port, [_port for (_port, _protocol) in existing_port_ids]) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: for range in added_ranges: self._source_port(True, _policy, portStr(range, "-"), protocol, transaction) for range in removed_ranges: self._source_port(False, _policy, portStr(range, "-"), protocol, transaction) for range in added_ranges: port_id = self.__source_port_id(range, protocol) self.__register_source_port(_obj, port_id, 0, None) transaction.add_fail(self.__unregister_source_port, _obj, port_id) for range in removed_ranges: port_id = self.__source_port_id(range, protocol) transaction.add_post(self.__unregister_source_port, _obj, port_id) if use_transaction is None: transaction.execute(True) return _policy def __unregister_source_port(self, _obj, port_id): if port_id in _obj.settings["source_ports"]: del _obj.settings["source_ports"][port_id] def query_source_port(self, policy, port, protocol): for (_port, _protocol) in self.get_settings(policy)["source_ports"]: if portInPortRange(port, _port) and protocol == _protocol: return True return False def list_source_ports(self, policy): return list(self.get_settings(policy)["source_ports"].keys()) # MASQUERADE def __masquerade_id(self): return True def add_masquerade(self, policy, timeout=0, sender=None, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._policies[_policy] masquerade_id = self.__masquerade_id() if masquerade_id in _obj.settings["masquerade"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.ALREADY_ENABLED, "masquerade already enabled in '%s'" % _name) if not _obj.derived_from_zone: if "HOST" in _obj.settings["egress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for egress zone 'HOST'") if "HOST" in _obj.settings["ingress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for ingress zone 'HOST'") for zone in _obj.settings["ingress_zones"]: if zone == "ANY": continue if self._fw.zone.list_interfaces(zone): raise FirewallError(errors.INVALID_ZONE, "'masquerade' cannot be used in a policy if an ingress zone has assigned interfaces") if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._masquerade(True, _policy, transaction) self.__register_masquerade(_obj, masquerade_id, timeout, sender) transaction.add_fail(self.__unregister_masquerade, _obj, masquerade_id) if use_transaction is None: transaction.execute(True) return _policy def __register_masquerade(self, _obj, masquerade_id, timeout, sender): _obj.settings["masquerade"][masquerade_id] = \ self.__gen_settings(timeout, sender) def remove_masquerade(self, policy, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] masquerade_id = self.__masquerade_id() if masquerade_id not in _obj.settings["masquerade"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.NOT_ENABLED, "masquerade not enabled in '%s'" % _name) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._masquerade(False, _policy, transaction) transaction.add_post(self.__unregister_masquerade, _obj, masquerade_id) if use_transaction is None: transaction.execute(True) return _policy def __unregister_masquerade(self, _obj, masquerade_id): if masquerade_id in _obj.settings["masquerade"]: del _obj.settings["masquerade"][masquerade_id] def query_masquerade(self, policy): return self.__masquerade_id() in self.get_settings(policy)["masquerade"] # PORT FORWARDING def check_forward_port(self, ipv, port, protocol, toport=None, toaddr=None): self._fw.check_port(port) self._fw.check_tcpudp(protocol) if toport: self._fw.check_port(toport) if toaddr: if not check_single_address(ipv, toaddr): raise FirewallError(errors.INVALID_ADDR, toaddr) if not toport and not toaddr: raise FirewallError( errors.INVALID_FORWARD, "port-forwarding is missing to-port AND to-addr") def __forward_port_id(self, port, protocol, toport=None, toaddr=None): if check_single_address("ipv6", toaddr): self.check_forward_port("ipv6", port, protocol, toport, toaddr) else: self.check_forward_port("ipv4", port, protocol, toport, toaddr) return (portStr(port, "-"), protocol, portStr(toport, "-"), str(toaddr)) def add_forward_port(self, policy, port, protocol, toport=None, toaddr=None, timeout=0, sender=None, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._policies[_policy] forward_id = self.__forward_port_id(port, protocol, toport, toaddr) if forward_id in _obj.settings["forward_ports"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.ALREADY_ENABLED, "'%s:%s:%s:%s' already in '%s'" % \ (port, protocol, toport, toaddr, _name)) if not _obj.derived_from_zone: if "HOST" in _obj.settings["egress_zones"]: if toaddr: raise FirewallError(errors.INVALID_FORWARD, "A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'") elif _obj.settings["egress_zones"]: if not toaddr: raise FirewallError(errors.INVALID_FORWARD, "'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone") for zone in _obj.settings["egress_zones"]: if zone == "ANY": continue if self._fw.zone.list_interfaces(zone): raise FirewallError(errors.INVALID_ZONE, "'forward-port' cannot be used in a policy if an egress zone has assigned interfaces") if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._forward_port(True, _policy, transaction, port, protocol, toport, toaddr) self.__register_forward_port(_obj, forward_id, timeout, sender) transaction.add_fail(self.__unregister_forward_port, _obj, forward_id) if use_transaction is None: transaction.execute(True) return _policy def __register_forward_port(self, _obj, forward_id, timeout, sender): _obj.settings["forward_ports"][forward_id] = \ self.__gen_settings(timeout, sender) def remove_forward_port(self, policy, port, protocol, toport=None, toaddr=None, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] forward_id = self.__forward_port_id(port, protocol, toport, toaddr) if forward_id not in _obj.settings["forward_ports"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.NOT_ENABLED, "'%s:%s:%s:%s' not in '%s'" % \ (port, protocol, toport, toaddr, _name)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._forward_port(False, _policy, transaction, port, protocol, toport, toaddr) transaction.add_post(self.__unregister_forward_port, _obj, forward_id) if use_transaction is None: transaction.execute(True) return _policy def __unregister_forward_port(self, _obj, forward_id): if forward_id in _obj.settings["forward_ports"]: del _obj.settings["forward_ports"][forward_id] def query_forward_port(self, policy, port, protocol, toport=None, toaddr=None): forward_id = self.__forward_port_id(port, protocol, toport, toaddr) return forward_id in self.get_settings(policy)["forward_ports"] def list_forward_ports(self, policy): return list(self.get_settings(policy)["forward_ports"].keys()) # ICMP BLOCK def check_icmp_block(self, icmp): self._fw.check_icmptype(icmp) def __icmp_block_id(self, icmp): self.check_icmp_block(icmp) return icmp def add_icmp_block(self, policy, icmp, timeout=0, sender=None, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._policies[_policy] icmp_id = self.__icmp_block_id(icmp) if icmp_id in _obj.settings["icmp_blocks"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.ALREADY_ENABLED, "'%s' already in '%s'" % (icmp, _name)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._icmp_block(True, _policy, icmp, transaction) self.__register_icmp_block(_obj, icmp_id, timeout, sender) transaction.add_fail(self.__unregister_icmp_block, _obj, icmp_id) if use_transaction is None: transaction.execute(True) return _policy def __register_icmp_block(self, _obj, icmp_id, timeout, sender): _obj.settings["icmp_blocks"][icmp_id] = \ self.__gen_settings(timeout, sender) def remove_icmp_block(self, policy, icmp, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] icmp_id = self.__icmp_block_id(icmp) if icmp_id not in _obj.settings["icmp_blocks"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (icmp, _name)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._icmp_block(False, _policy, icmp, transaction) transaction.add_post(self.__unregister_icmp_block, _obj, icmp_id) if use_transaction is None: transaction.execute(True) return _policy def __unregister_icmp_block(self, _obj, icmp_id): if icmp_id in _obj.settings["icmp_blocks"]: del _obj.settings["icmp_blocks"][icmp_id] def query_icmp_block(self, policy, icmp): return self.__icmp_block_id(icmp) in self.get_settings(policy)["icmp_blocks"] def list_icmp_blocks(self, policy): return self.get_settings(policy)["icmp_blocks"].keys() # ICMP BLOCK INVERSION def __icmp_block_inversion_id(self): return True def add_icmp_block_inversion(self, policy, sender=None, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] icmp_block_inversion_id = self.__icmp_block_inversion_id() if icmp_block_inversion_id in _obj.settings["icmp_block_inversion"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError( errors.ALREADY_ENABLED, "icmp-block-inversion already enabled in '%s'" % _name) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: # undo icmp blocks for args in self.get_settings(_policy)["icmp_blocks"]: self._icmp_block(False, _policy, args, transaction) self._icmp_block_inversion(False, _policy, transaction) self.__register_icmp_block_inversion(_obj, icmp_block_inversion_id, sender) transaction.add_fail(self.__undo_icmp_block_inversion, _policy, _obj, icmp_block_inversion_id) # redo icmp blocks if _obj.applied: for args in self.get_settings(_policy)["icmp_blocks"]: self._icmp_block(True, _policy, args, transaction) self._icmp_block_inversion(True, _policy, transaction) if use_transaction is None: transaction.execute(True) return _policy def __register_icmp_block_inversion(self, _obj, icmp_block_inversion_id, sender): _obj.settings["icmp_block_inversion"][icmp_block_inversion_id] = \ self.__gen_settings(0, sender) def __undo_icmp_block_inversion(self, _policy, _obj, icmp_block_inversion_id): transaction = self.new_transaction() # undo icmp blocks if _obj.applied: for args in self.get_settings(_policy)["icmp_blocks"]: self._icmp_block(False, _policy, args, transaction) if icmp_block_inversion_id in _obj.settings["icmp_block_inversion"]: del _obj.settings["icmp_block_inversion"][icmp_block_inversion_id] # redo icmp blocks if _obj.applied: for args in self.get_settings(_policy)["icmp_blocks"]: self._icmp_block(True, _policy, args, transaction) transaction.execute(True) def remove_icmp_block_inversion(self, policy, use_transaction=None): _policy = self._fw.check_policy(policy) self._fw.check_panic() _obj = self._policies[_policy] icmp_block_inversion_id = self.__icmp_block_inversion_id() if icmp_block_inversion_id not in _obj.settings["icmp_block_inversion"]: _name = _obj.derived_from_zone if _obj.derived_from_zone else _policy raise FirewallError( errors.NOT_ENABLED, "icmp-block-inversion not enabled in '%s'" % _name) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: # undo icmp blocks for args in self.get_settings(_policy)["icmp_blocks"]: self._icmp_block(False, _policy, args, transaction) self._icmp_block_inversion(False, _policy, transaction) self.__unregister_icmp_block_inversion(_obj, icmp_block_inversion_id) transaction.add_fail(self.__register_icmp_block_inversion, _obj, icmp_block_inversion_id, None) # redo icmp blocks if _obj.applied: for args in self.get_settings(_policy)["icmp_blocks"]: self._icmp_block(True, _policy, args, transaction) self._icmp_block_inversion(True, _policy, transaction) if use_transaction is None: transaction.execute(True) return _policy def __unregister_icmp_block_inversion(self, _obj, icmp_block_inversion_id): if icmp_block_inversion_id in _obj.settings["icmp_block_inversion"]: del _obj.settings["icmp_block_inversion"][icmp_block_inversion_id] def query_icmp_block_inversion(self, policy): return self.__icmp_block_inversion_id() in \ self.get_settings(policy)["icmp_block_inversion"] def gen_chain_rules(self, policy, create, table, chain, transaction): obj = self._fw.policy.get_policy(policy) if obj.derived_from_zone: # For policies derived from zones, use only the first policy in the # list to track chain creation. The chain names are converted to # zone-based names as such they're "global" for all zone derived # policies. tracking_policy = self._fw.zone._zone_policies[obj.derived_from_zone][0] else: tracking_policy = policy if create: if tracking_policy in self._chains and \ (table, chain) in self._chains[tracking_policy]: return else: if tracking_policy not in self._chains or \ (table, chain) not in self._chains[tracking_policy]: return for backend in self._fw.enabled_backends(): if backend.policies_supported and \ table in backend.get_available_tables(): rules = backend.build_policy_chain_rules(create, policy, table, chain) transaction.add_rules(backend, rules) self._register_chains(tracking_policy, create, [(table, chain)]) transaction.add_fail(self._register_chains, tracking_policy, not create, [(table, chain)]) def _register_chains(self, policy, create, tables): for (table, chain) in tables: if create: self._chains.setdefault(policy, []).append((table, chain)) else: self._chains[policy].remove((table, chain)) if len(self._chains[policy]) == 0: del self._chains[policy] # IPSETS def _ipset_family(self, name): if self._fw.ipset.get_type(name) == "hash:mac": return None return self._fw.ipset.get_family(name) def __ipset_type(self, name): return self._fw.ipset.get_type(name) def _ipset_match_flags(self, name, flag): return ",".join([flag] * self._fw.ipset.get_dimension(name)) def _check_ipset_applied(self, name): return self._fw.ipset.check_applied(name) def _check_ipset_type_for_source(self, name): _type = self.__ipset_type(name) if _type not in SOURCE_IPSET_TYPES: raise FirewallError( errors.INVALID_IPSET, "ipset '%s' with type '%s' not usable as source" % \ (name, _type)) def _rule_prepare(self, enable, policy, rule, transaction, included_services=None): # First apply any services this service may include if type(rule.element) == Rich_Service: svc = self._fw.service.get_service(rule.element.name) if included_services is None: included_services = [rule.element.name] for include in svc.includes: if include in included_services: continue self.check_service(include) included_services.append(include) _rule = copy.deepcopy(rule) _rule.element.name = include self._rule_prepare(enable, policy, _rule, transaction, included_services=included_services) ipvs = [] if rule.family: ipvs = [ rule.family ] elif rule.element and (isinstance(rule.element, Rich_IcmpBlock) or isinstance(rule.element, Rich_IcmpType)): ict = self._fw.config.get_icmptype(rule.element.name) if ict.destination: ipvs = [ipv for ipv in ["ipv4", "ipv6"] if ipv in ict.destination] source_ipv = self._rule_source_ipv(rule.source) if source_ipv: if rule.family: # rule family is defined by user, no way to change it if rule.family != source_ipv: raise FirewallError(errors.INVALID_RULE, "Source address family '%s' conflicts with rule family '%s'." % (source_ipv, rule.family)) else: # use the source family as rule family ipvs = [ source_ipv ] if not ipvs: ipvs = ["ipv4", "ipv6"] # clamp ipvs to those that are actually enabled. ipvs = [ipv for ipv in ipvs if self._fw.is_ipv_enabled(ipv)] # add an element to object to allow backends to know what ipvs this applies to rule.ipvs = ipvs for backend in set([self._fw.get_backend_by_ipv(x) for x in ipvs]): # SERVICE if type(rule.element) == Rich_Service: svc = self._fw.service.get_service(rule.element.name) destinations = [] if len(svc.destination) > 0: if rule.destination: # we can not use two destinations at the same time raise FirewallError(errors.INVALID_RULE, "Destination conflict with service.") for ipv in ipvs: if ipv in svc.destination and backend.is_ipv_supported(ipv): destinations.append(svc.destination[ipv]) else: # dummy for the following for loop destinations.append(None) for destination in destinations: if type(rule.action) == Rich_Accept: # only load modules for accept action helpers = self.get_helpers_for_service_modules(svc.modules, enable) helpers += self.get_helpers_for_service_helpers(svc.helpers) helpers = sorted(set(helpers), key=lambda x: x.name) modules = [ ] for helper in helpers: module = helper.module _module_short_name = get_nf_conntrack_short_name(module) nat_module = module.replace("conntrack", "nat") modules.append(nat_module) if helper.family != "" and not backend.is_ipv_supported(helper.family): # no support for family ipv, continue continue if len(helper.ports) < 1: modules.append(module) else: for (port,proto) in helper.ports: rules = backend.build_policy_helper_ports_rules( enable, policy, proto, port, destination, helper.name, _module_short_name) transaction.add_rules(backend, rules) transaction.add_modules(modules) # create rules for (port,proto) in svc.ports: rules = backend.build_policy_ports_rules( enable, policy, proto, port, destination, rule) transaction.add_rules(backend, rules) for proto in svc.protocols: rules = backend.build_policy_protocol_rules( enable, policy, proto, destination, rule) transaction.add_rules(backend, rules) # create rules for (port,proto) in svc.source_ports: rules = backend.build_policy_source_ports_rules( enable, policy, proto, port, destination, rule) transaction.add_rules(backend, rules) # PORT elif type(rule.element) == Rich_Port: port = rule.element.port protocol = rule.element.protocol self.check_port(port, protocol) rules = backend.build_policy_ports_rules( enable, policy, protocol, port, None, rule) transaction.add_rules(backend, rules) # PROTOCOL elif type(rule.element) == Rich_Protocol: protocol = rule.element.value self.check_protocol(protocol) rules = backend.build_policy_protocol_rules( enable, policy, protocol, None, rule) transaction.add_rules(backend, rules) # MASQUERADE elif type(rule.element) == Rich_Masquerade: if enable: for ipv in ipvs: if backend.is_ipv_supported(ipv): transaction.add_post(enable_ip_forwarding, ipv) rules = backend.build_policy_masquerade_rules(enable, policy, rule) transaction.add_rules(backend, rules) # FORWARD PORT elif type(rule.element) == Rich_ForwardPort: port = rule.element.port protocol = rule.element.protocol toport = rule.element.to_port toaddr = rule.element.to_address for ipv in ipvs: if backend.is_ipv_supported(ipv): self.check_forward_port(ipv, port, protocol, toport, toaddr) if toaddr and enable: transaction.add_post(enable_ip_forwarding, ipv) rules = backend.build_policy_forward_port_rules( enable, policy, port, protocol, toport, toaddr, rule) transaction.add_rules(backend, rules) # SOURCE PORT elif type(rule.element) == Rich_SourcePort: port = rule.element.port protocol = rule.element.protocol self.check_port(port, protocol) rules = backend.build_policy_source_ports_rules( enable, policy, protocol, port, None, rule) transaction.add_rules(backend, rules) # ICMP BLOCK and ICMP TYPE elif type(rule.element) == Rich_IcmpBlock or \ type(rule.element) == Rich_IcmpType: ict = self._fw.config.get_icmptype(rule.element.name) if rule.family and ict.destination and \ rule.family not in ict.destination: raise FirewallError(errors.INVALID_ICMPTYPE, "rich rule family '%s' conflicts with icmp type '%s'" % \ (rule.family, rule.element.name)) if type(rule.element) == Rich_IcmpBlock and \ rule.action and type(rule.action) == Rich_Accept: # icmp block might have reject or drop action, but not accept raise FirewallError(errors.INVALID_RULE, "IcmpBlock not usable with accept action") rules = backend.build_policy_icmp_block_rules(enable, policy, ict, rule) transaction.add_rules(backend, rules) elif rule.element is None: rules = backend.build_policy_rich_source_destination_rules( enable, policy, rule) transaction.add_rules(backend, rules) # EVERYTHING ELSE else: raise FirewallError(errors.INVALID_RULE, "Unknown element %s" % type(rule.element)) def _service(self, enable, policy, service, transaction, included_services=None): svc = self._fw.service.get_service(service) helpers = self.get_helpers_for_service_modules(svc.modules, enable) helpers += self.get_helpers_for_service_helpers(svc.helpers) helpers = sorted(set(helpers), key=lambda x: x.name) # First apply any services this service may include if included_services is None: included_services = [service] for include in svc.includes: if include in included_services: continue self.check_service(include) included_services.append(include) self._service(enable, policy, include, transaction, included_services=included_services) # build a list of (backend, destination). The destination may be ipv4, # ipv6 or None # backends_ipv = [] for ipv in ["ipv4", "ipv6"]: if not self._fw.is_ipv_enabled(ipv): continue backend = self._fw.get_backend_by_ipv(ipv) if len(svc.destination) > 0: if ipv in svc.destination: backends_ipv.append((backend, svc.destination[ipv])) else: if (backend, None) not in backends_ipv: backends_ipv.append((backend, None)) for (backend,destination) in backends_ipv: for helper in helpers: module = helper.module _module_short_name = get_nf_conntrack_short_name(module) nat_module = helper.module.replace("conntrack", "nat") transaction.add_module(nat_module) if helper.family != "" and not backend.is_ipv_supported(helper.family): # no support for family ipv, continue continue if len(helper.ports) < 1: transaction.add_module(module) else: for (port,proto) in helper.ports: rules = backend.build_policy_helper_ports_rules( enable, policy, proto, port, destination, helper.name, _module_short_name) transaction.add_rules(backend, rules) for (port,proto) in svc.ports: rules = backend.build_policy_ports_rules(enable, policy, proto, port, destination) transaction.add_rules(backend, rules) for protocol in svc.protocols: rules = backend.build_policy_protocol_rules( enable, policy, protocol, destination) transaction.add_rules(backend, rules) for (port,proto) in svc.source_ports: rules = backend.build_policy_source_ports_rules( enable, policy, proto, port, destination) transaction.add_rules(backend, rules) def _port(self, enable, policy, port, protocol, transaction): for backend in self._fw.enabled_backends(): if not backend.policies_supported: continue rules = backend.build_policy_ports_rules(enable, policy, protocol, port) transaction.add_rules(backend, rules) def _protocol(self, enable, policy, protocol, transaction): for backend in self._fw.enabled_backends(): if not backend.policies_supported: continue rules = backend.build_policy_protocol_rules(enable, policy, protocol) transaction.add_rules(backend, rules) def _source_port(self, enable, policy, port, protocol, transaction): for backend in self._fw.enabled_backends(): if not backend.policies_supported: continue rules = backend.build_policy_source_ports_rules(enable, policy, protocol, port) transaction.add_rules(backend, rules) def _masquerade(self, enable, policy, transaction): ipv = "ipv4" transaction.add_post(enable_ip_forwarding, ipv) backend = self._fw.get_backend_by_ipv(ipv) rules = backend.build_policy_masquerade_rules(enable, policy) transaction.add_rules(backend, rules) def _forward_port(self, enable, policy, transaction, port, protocol, toport=None, toaddr=None): if check_single_address("ipv6", toaddr): ipv = "ipv6" else: ipv = "ipv4" if toaddr and enable: transaction.add_post(enable_ip_forwarding, ipv) backend = self._fw.get_backend_by_ipv(ipv) rules = backend.build_policy_forward_port_rules( enable, policy, port, protocol, toport, toaddr) transaction.add_rules(backend, rules) def _icmp_block(self, enable, policy, icmp, transaction): ict = self._fw.config.get_icmptype(icmp) for backend in self._fw.enabled_backends(): if not backend.policies_supported: continue skip_backend = False if ict.destination: for ipv in ["ipv4", "ipv6"]: if ipv in ict.destination: if not backend.is_ipv_supported(ipv): skip_backend = True break if skip_backend: continue rules = backend.build_policy_icmp_block_rules(enable, policy, ict) transaction.add_rules(backend, rules) def _icmp_block_inversion(self, enable, policy, transaction): target = self._policies[policy].target # Do not add general icmp accept rules into a trusted, block or drop # policy. if target in [ "DROP", "%%REJECT%%", "REJECT" ]: return if not self.query_icmp_block_inversion(policy) and target == "ACCEPT": # ibi target and policy target are ACCEPT, no need to add an extra # rule return for backend in self._fw.enabled_backends(): if not backend.policies_supported: continue rules = backend.build_policy_icmp_block_inversion_rules(enable, policy) transaction.add_rules(backend, rules) def check_ingress_egress(self, policy, ingress_zones, egress_zones, ingress_interfaces, egress_interfaces, ingress_sources, egress_sources): for zone in ingress_zones: self.check_ingress_zone(zone) for zone in egress_zones: self.check_egress_zone(zone) if ("ANY" in ingress_zones or "HOST" in ingress_zones) and \ len(ingress_zones) > 1: raise FirewallError(errors.INVALID_ZONE, "'ingress-zones' may only contain one of: many regular zones, ANY, or HOST") if ("ANY" in egress_zones or "HOST" in egress_zones) and \ len(egress_zones) > 1: raise FirewallError(errors.INVALID_ZONE, "'egress-zones' may only contain one of: many regular zones, ANY, or HOST") if (egress_interfaces or egress_sources) and \ not ingress_interfaces and not ingress_sources and \ "HOST" not in ingress_zones and "ANY" not in ingress_zones: raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" has no ingress" % (policy)) if (ingress_interfaces or ingress_sources) and \ not egress_interfaces and not egress_sources and \ "HOST" not in egress_zones and "ANY" not in egress_zones: raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" has no egress" % (policy)) def check_ingress_egress_chain(self, policy, table, chain, ingress_zones, egress_zones, ingress_interfaces, egress_interfaces, ingress_sources, egress_sources): if chain == "PREROUTING": # raw,prerouting is used for conntrack helpers (services), so we # need to allow it if egress-zones contains an actual zone if table != "raw": if egress_interfaces: raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" egress-zones may not include a zone with added interfaces." % (policy)) elif chain == "POSTROUTING": if "HOST" in ingress_zones: raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" ingress-zones may not include HOST." % (policy)) if "HOST" in egress_zones: raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" egress-zones may not include HOST." % (policy)) if ingress_interfaces: raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" ingress-zones may not include a zone with added interfaces." % (policy)) elif chain == "FORWARD": if "HOST" in ingress_zones: raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" ingress-zones may not include HOST." % (policy)) if "HOST" in egress_zones: raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" egress-zones may not include HOST." % (policy)) elif chain == "INPUT": if "HOST" not in egress_zones: raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" egress-zones must include only HOST." % (policy)) elif chain == "OUTPUT": if "HOST" not in ingress_zones: raise FirewallError(errors.INVALID_ZONE, "policy \"%s\" ingress-zones must include only HOST." % (policy)) def _ingress_egress_zones_transaction(self, enable, policy): transaction = self.new_transaction() self._ingress_egress_zones(enable, policy, transaction) transaction.execute(True) def _ingress_egress_zones(self, enable, policy, transaction): obj = self._policies[policy] ingress_zones = obj.settings["ingress_zones"] egress_zones = obj.settings["egress_zones"] ingress_interfaces = set() egress_interfaces = set() ingress_sources = set() egress_sources = set() for zone in ingress_zones: if zone in ["ANY", "HOST"]: continue ingress_interfaces |= set(self._fw.zone.list_interfaces(zone)) ingress_sources |= set(self._fw.zone.list_sources(zone)) for zone in egress_zones: if zone in ["ANY", "HOST"]: continue egress_interfaces |= set(self._fw.zone.list_interfaces(zone)) egress_sources |= set(self._fw.zone.list_sources(zone)) self.check_ingress_egress(policy, ingress_zones, egress_zones, ingress_interfaces, egress_interfaces, ingress_sources, egress_sources) for backend in self._fw.enabled_backends(): if not backend.policies_supported: continue for (table, chain) in self._get_table_chains_for_policy_dispatch(policy): self.check_ingress_egress_chain(policy, table, chain, ingress_zones, egress_zones, ingress_interfaces, egress_interfaces, ingress_sources, egress_sources) rules = backend.build_policy_ingress_egress_rules(enable, policy, table, chain, ingress_interfaces, egress_interfaces, ingress_sources, egress_sources) transaction.add_rules(backend, rules) def _get_table_chains_for_policy_dispatch(self, policy): """Create a list of (table, chain) needed for policy dispatch""" obj = self._policies[policy] if "ANY" in obj.settings["ingress_zones"] and "HOST" in obj.settings["egress_zones"]: # any --> HOST tc = [("filter", "INPUT"), ("nat", "PREROUTING"), ("mangle", "PREROUTING")] # iptables backend needs to put conntrack helper rules in raw # prerouting. if not self._fw.nftables_enabled: tc.append(("raw", "PREROUTING")) return tc elif "HOST" in obj.settings["egress_zones"]: # zone --> HOST tc = [("filter", "INPUT")] # iptables backend needs to put conntrack helper rules in raw # prerouting. if not self._fw.nftables_enabled: tc.append(("raw", "PREROUTING")) return tc elif "HOST" in obj.settings["ingress_zones"]: # HOST --> zone/any return [("filter", "OUTPUT")] elif "ANY" in obj.settings["ingress_zones"] and "ANY" in obj.settings["egress_zones"]: # any --> any tc = [("filter", "FORWARD"), ("nat", "PREROUTING"), ("nat", "POSTROUTING"), ("mangle", "PREROUTING")] # iptables backend needs to put conntrack helper rules in raw # prerouting. if not self._fw.nftables_enabled: tc.append(("raw", "PREROUTING")) return tc elif "ANY" in obj.settings["egress_zones"]: # zone --> any tc = [("filter", "FORWARD"), ("nat", "PREROUTING"), ("mangle", "PREROUTING")] # iptables backend needs to put conntrack helper rules in raw # prerouting. if not self._fw.nftables_enabled: tc.append(("raw", "PREROUTING")) for zone in obj.settings["ingress_zones"]: if self._fw.zone.get_settings(zone)["interfaces"]: break else: tc.append(("nat", "POSTROUTING")) return tc elif "ANY" in obj.settings["ingress_zones"]: # any --> zone tc = [("filter", "FORWARD"), ("nat", "POSTROUTING")] # iptables backend needs to put conntrack helper rules in raw # prerouting. if not self._fw.nftables_enabled: tc.append(("raw", "PREROUTING")) for zone in obj.settings["egress_zones"]: if self._fw.zone.get_settings(zone)["interfaces"]: break else: tc.append(("nat", "PREROUTING")) tc.append(("mangle", "PREROUTING")) return tc else: # zone -> zone tc = [("filter", "FORWARD")] # iptables backend needs to put conntrack helper rules in raw # prerouting. if not self._fw.nftables_enabled: tc.append(("raw", "PREROUTING")) for zone in obj.settings["ingress_zones"]: if self._fw.zone.get_settings(zone)["interfaces"]: break else: tc.append(("nat", "POSTROUTING")) for zone in obj.settings["egress_zones"]: if self._fw.zone.get_settings(zone)["interfaces"]: break else: tc.append(("nat", "PREROUTING")) tc.append(("mangle", "PREROUTING")) return tc def _get_table_chains_for_zone_dispatch(self, policy): """Create a list of (table, chain) needed for zone dispatch""" obj = self._policies[policy] if "HOST" in obj.settings["egress_zones"]: # zone --> Host tc = [("filter", "INPUT")] # iptables backend needs to put conntrack helper rules in raw # prerouting. if not self._fw.nftables_enabled: tc.append(("raw", "PREROUTING")) return tc elif "ANY" in obj.settings["egress_zones"]: # zone --> any return [("filter", "FORWARD_IN"), ("nat", "PREROUTING"), ("mangle", "PREROUTING")] elif "ANY" in obj.settings["ingress_zones"]: # any --> zone return [("filter", "FORWARD_OUT"), ("nat", "POSTROUTING")] else: return FirewallError("Invalid policy: %s" % (policy)) def policy_base_chain_name(self, policy, table, policy_prefix, isSNAT=False): obj = self._fw.policy.get_policy(policy) if obj.derived_from_zone: suffix = obj.derived_from_zone else: suffix = policy_prefix + policy if "HOST" in obj.settings["egress_zones"]: # zone/any --> Host if table == "filter": return "IN_" + suffix if table == "raw": # NOTE: nftables doesn't actually use this. Only iptables return "PRE_" + suffix if not obj.derived_from_zone: if table in ["mangle", "nat"]: return "PRE_" + suffix elif "HOST" in obj.settings["ingress_zones"]: # HOST --> zone/any if not obj.derived_from_zone: if table == "filter": return "OUT_" + suffix elif "ANY" in obj.settings["egress_zones"]: # zone/any --> any if table == "filter": if obj.derived_from_zone: return "FWDI_" + suffix else: return "FWD_" + suffix elif table == "nat": if isSNAT: return "POST_" + suffix else: return "PRE_" + suffix elif table in ["mangle", "raw"]: return "PRE_" + suffix elif "ANY" in obj.settings["ingress_zones"]: # any --> zone if table == "filter": if obj.derived_from_zone: return "FWDO_" + suffix else: return "FWD_" + suffix elif table == "nat": if isSNAT: return "POST_" + suffix else: return "PRE_" + suffix elif table in ["mangle", "raw"]: if not obj.derived_from_zone: return "PRE_" + suffix elif not obj.derived_from_zone: # zone --> zone if table == "filter": return "FWD_" + suffix elif table == "nat": if isSNAT: return "POST_" + suffix else: return "PRE_" + suffix elif table in ["mangle", "raw"]: return "PRE_" + suffix return FirewallError("Can't convert policy to chain name: %s, %s, %s" % (policy, table, isSNAT)) PKpge[Uе fw_icmptype.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "FirewallIcmpType" ] from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError class FirewallIcmpType(object): def __init__(self, fw): self._fw = fw self._icmptypes = { } def __repr__(self): return '%s(%r)' % (self.__class__, self._icmptypes) def cleanup(self): self._icmptypes.clear() # zones def get_icmptypes(self): return sorted(self._icmptypes.keys()) def check_icmptype(self, icmptype): if icmptype not in self._icmptypes: raise FirewallError(errors.INVALID_ICMPTYPE, icmptype) def get_icmptype(self, icmptype): self.check_icmptype(icmptype) return self._icmptypes[icmptype] def add_icmptype(self, obj): orig_ipvs = obj.destination if len(orig_ipvs) == 0: orig_ipvs = [ "ipv4", "ipv6" ] for ipv in orig_ipvs: if ipv == "ipv4": if not self._fw.ip4tables_enabled and not self._fw.nftables_enabled: continue supported_icmps = self._fw.ipv4_supported_icmp_types elif ipv == "ipv6": if not self._fw.ip6tables_enabled and not self._fw.nftables_enabled: continue supported_icmps = self._fw.ipv6_supported_icmp_types else: supported_icmps = [ ] if obj.name.lower() not in supported_icmps: log.info1("ICMP type '%s' is not supported by the kernel for %s." % (obj.name, ipv)) self._icmptypes[obj.name] = obj def remove_icmptype(self, icmptype): self.check_icmptype(icmptype) del self._icmptypes[icmptype] PKpge[gg fw_service.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "FirewallService" ] from firewall import errors from firewall.errors import FirewallError class FirewallService(object): def __init__(self, fw): self._fw = fw self._services = { } def __repr__(self): return '%s(%r)' % (self.__class__, self._services) def cleanup(self): self._services.clear() # zones def get_services(self): return sorted(self._services.keys()) def check_service(self, service): if service not in self._services: raise FirewallError(errors.INVALID_SERVICE, service) def get_service(self, service): self.check_service(service) return self._services[service] def add_service(self, obj): self._services[obj.name] = obj def remove_service(self, service): self.check_service(service) del self._services[service] PKpge[3 nftables.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2018 Red Hat, Inc. # # Authors: # Eric Garver # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # from __future__ import absolute_import import copy import json import ipaddress from firewall.core.logger import log from firewall.functions import check_mac, getPortRange, normalizeIP6, \ check_single_address, check_address from firewall.errors import FirewallError, UNKNOWN_ERROR, INVALID_RULE, \ INVALID_ICMPTYPE, INVALID_TYPE, INVALID_ENTRY, \ INVALID_PORT from firewall.core.rich import Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark, \ Rich_Masquerade, Rich_ForwardPort, Rich_IcmpBlock from nftables.nftables import Nftables TABLE_NAME = "firewalld" TABLE_NAME_POLICY = TABLE_NAME + "_" + "policy_drop" POLICY_CHAIN_PREFIX = "policy_" # Map iptables (table, chain) to hooks and priorities. # These are well defined by NF_IP_PRI_* defines in netfilter. # # This is analogous to ipXtables.BUILT_IN_CHAINS, but we omit the chains that # are only used for direct rules. # # Note: All hooks use their standard position + NFT_HOOK_OFFSET. This means # iptables will have DROP precedence. It also means that even if iptables # ACCEPTs a packet it may still be dropped later by firewalld's rules. # NFT_HOOK_OFFSET = 10 IPTABLES_TO_NFT_HOOK = { #"security": { # "INPUT": ("input", 50 + NFT_HOOK_OFFSET), # "OUTPUT": ("output", 50 + NFT_HOOK_OFFSET), # "FORWARD": ("forward", 50 + NFT_HOOK_OFFSET), #}, "raw": { # "PREROUTING": ("prerouting", -300 + NFT_HOOK_OFFSET), # "OUTPUT": ("output", -300 + NFT_HOOK_OFFSET), }, "mangle": { "PREROUTING": ("prerouting", -150 + NFT_HOOK_OFFSET), # "POSTROUTING": ("postrouting", -150 + NFT_HOOK_OFFSET), # "INPUT": ("input", -150 + NFT_HOOK_OFFSET), # "OUTPUT": ("output", -150 + NFT_HOOK_OFFSET), # "FORWARD": ("forward", -150 + NFT_HOOK_OFFSET), }, "nat": { "PREROUTING": ("prerouting", -100 + NFT_HOOK_OFFSET), "POSTROUTING": ("postrouting", 100 + NFT_HOOK_OFFSET), # "INPUT": ("input", 100 + NFT_HOOK_OFFSET), # "OUTPUT": ("output", -100 + NFT_HOOK_OFFSET), }, "filter": { "PREROUTING": ("prerouting", 0 + NFT_HOOK_OFFSET), "INPUT": ("input", 0 + NFT_HOOK_OFFSET), "FORWARD": ("forward", 0 + NFT_HOOK_OFFSET), "OUTPUT": ("output", 0 + NFT_HOOK_OFFSET), }, } def _icmp_types_fragments(protocol, type, code=None): fragments = [{"match": {"left": {"payload": {"protocol": protocol, "field": "type"}}, "op": "==", "right": type}}] if code is not None: fragments.append({"match": {"left": {"payload": {"protocol": protocol, "field": "code"}}, "op": "==", "right": code}}) return fragments # Most ICMP types are provided by nft, but for the codes we have to use numeric # values. # ICMP_TYPES_FRAGMENTS = { "ipv4": { "communication-prohibited": _icmp_types_fragments("icmp", "destination-unreachable", 13), "destination-unreachable": _icmp_types_fragments("icmp", "destination-unreachable"), "echo-reply": _icmp_types_fragments("icmp", "echo-reply"), "echo-request": _icmp_types_fragments("icmp", "echo-request"), "fragmentation-needed": _icmp_types_fragments("icmp", "destination-unreachable", 4), "host-precedence-violation": _icmp_types_fragments("icmp", "destination-unreachable", 14), "host-prohibited": _icmp_types_fragments("icmp", "destination-unreachable", 10), "host-redirect": _icmp_types_fragments("icmp", "redirect", 1), "host-unknown": _icmp_types_fragments("icmp", "destination-unreachable", 7), "host-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 1), "ip-header-bad": _icmp_types_fragments("icmp", "parameter-problem", 1), "network-prohibited": _icmp_types_fragments("icmp", "destination-unreachable", 8), "network-redirect": _icmp_types_fragments("icmp", "redirect", 0), "network-unknown": _icmp_types_fragments("icmp", "destination-unreachable", 6), "network-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 0), "parameter-problem": _icmp_types_fragments("icmp", "parameter-problem"), "port-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 3), "precedence-cutoff": _icmp_types_fragments("icmp", "destination-unreachable", 15), "protocol-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 2), "redirect": _icmp_types_fragments("icmp", "redirect"), "required-option-missing": _icmp_types_fragments("icmp", "parameter-problem", 1), "router-advertisement": _icmp_types_fragments("icmp", "router-advertisement"), "router-solicitation": _icmp_types_fragments("icmp", "router-solicitation"), "source-quench": _icmp_types_fragments("icmp", "source-quench"), "source-route-failed": _icmp_types_fragments("icmp", "destination-unreachable", 5), "time-exceeded": _icmp_types_fragments("icmp", "time-exceeded"), "timestamp-reply": _icmp_types_fragments("icmp", "timestamp-reply"), "timestamp-request": _icmp_types_fragments("icmp", "timestamp-request"), "tos-host-redirect": _icmp_types_fragments("icmp", "redirect", 3), "tos-host-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 12), "tos-network-redirect": _icmp_types_fragments("icmp", "redirect", 2), "tos-network-unreachable": _icmp_types_fragments("icmp", "destination-unreachable", 11), "ttl-zero-during-reassembly": _icmp_types_fragments("icmp", "time-exceeded", 1), "ttl-zero-during-transit": _icmp_types_fragments("icmp", "time-exceeded", 0), }, "ipv6": { "address-unreachable": _icmp_types_fragments("icmpv6", "destination-unreachable", 3), "bad-header": _icmp_types_fragments("icmpv6", "parameter-problem", 0), "beyond-scope": _icmp_types_fragments("icmpv6", "destination-unreachable", 2), "communication-prohibited": _icmp_types_fragments("icmpv6", "destination-unreachable", 1), "destination-unreachable": _icmp_types_fragments("icmpv6", "destination-unreachable"), "echo-reply": _icmp_types_fragments("icmpv6", "echo-reply"), "echo-request": _icmp_types_fragments("icmpv6", "echo-request"), "failed-policy": _icmp_types_fragments("icmpv6", "destination-unreachable", 5), "mld-listener-done": _icmp_types_fragments("icmpv6", "mld-listener-done"), "mld-listener-query": _icmp_types_fragments("icmpv6", "mld-listener-query"), "mld-listener-report": _icmp_types_fragments("icmpv6", "mld-listener-report"), "mld2-listener-report": _icmp_types_fragments("icmpv6", "mld2-listener-report"), "neighbour-advertisement": _icmp_types_fragments("icmpv6", "nd-neighbor-advert"), "neighbour-solicitation": _icmp_types_fragments("icmpv6", "nd-neighbor-solicit"), "no-route": _icmp_types_fragments("icmpv6", "destination-unreachable", 0), "packet-too-big": _icmp_types_fragments("icmpv6", "packet-too-big"), "parameter-problem": _icmp_types_fragments("icmpv6", "parameter-problem"), "port-unreachable": _icmp_types_fragments("icmpv6", "destination-unreachable", 4), "redirect": _icmp_types_fragments("icmpv6", "nd-redirect"), "reject-route": _icmp_types_fragments("icmpv6", "destination-unreachable", 6), "router-advertisement": _icmp_types_fragments("icmpv6", "nd-router-advert"), "router-solicitation": _icmp_types_fragments("icmpv6", "nd-router-solicit"), "time-exceeded": _icmp_types_fragments("icmpv6", "time-exceeded"), "ttl-zero-during-reassembly": _icmp_types_fragments("icmpv6", "time-exceeded", 1), "ttl-zero-during-transit": _icmp_types_fragments("icmpv6", "time-exceeded", 0), "unknown-header-type": _icmp_types_fragments("icmpv6", "parameter-problem", 1), "unknown-option": _icmp_types_fragments("icmpv6", "parameter-problem", 2), } } class nftables(object): name = "nftables" policies_supported = True def __init__(self, fw): self._fw = fw self.restore_command_exists = True self.available_tables = [] self.rule_to_handle = {} self.rule_ref_count = {} self.rich_rule_priority_counts = {} self.policy_priority_counts = {} self.zone_source_index_cache = {} self.created_tables = {"inet": [], "ip": [], "ip6": []} self.nftables = Nftables() self.nftables.set_echo_output(True) self.nftables.set_handle_output(True) def _run_replace_zone_source(self, rule, zone_source_index_cache): for verb in ["add", "insert", "delete"]: if verb in rule: break if "%%ZONE_SOURCE%%" in rule[verb]["rule"]: zone_source = (rule[verb]["rule"]["%%ZONE_SOURCE%%"]["zone"], rule[verb]["rule"]["%%ZONE_SOURCE%%"]["address"]) del rule[verb]["rule"]["%%ZONE_SOURCE%%"] elif "%%ZONE_INTERFACE%%" in rule[verb]["rule"]: zone_source = None del rule[verb]["rule"]["%%ZONE_INTERFACE%%"] else: return family = rule[verb]["rule"]["family"] if zone_source and verb == "delete": if family in zone_source_index_cache and \ zone_source in zone_source_index_cache[family]: zone_source_index_cache[family].remove(zone_source) elif verb != "delete": if family not in zone_source_index_cache: zone_source_index_cache[family] = [] if zone_source: # order source based dispatch by zone name if zone_source not in zone_source_index_cache[family]: zone_source_index_cache[family].append(zone_source) zone_source_index_cache[family].sort(key=lambda x: x[0]) index = zone_source_index_cache[family].index(zone_source) else: if self._fw._allow_zone_drifting: index = 0 else: index = len(zone_source_index_cache[family]) _verb_snippet = rule[verb] del rule[verb] if index == 0: rule["insert"] = _verb_snippet else: index -= 1 # point to the rule before insertion point rule["add"] = _verb_snippet rule["add"]["rule"]["index"] = index def reverse_rule(self, dict): if "insert" in dict: return {"delete": copy.deepcopy(dict["insert"])} elif "add" in dict: return {"delete": copy.deepcopy(dict["add"])} else: raise FirewallError(UNKNOWN_ERROR, "Failed to reverse rule") def _set_rule_replace_priority(self, rule, priority_counts, token): for verb in ["add", "insert", "delete"]: if verb in rule: break if token in rule[verb]["rule"]: priority = rule[verb]["rule"][token] del rule[verb]["rule"][token] if type(priority) != int: raise FirewallError(INVALID_RULE, "priority must be followed by a number") chain = (rule[verb]["rule"]["family"], rule[verb]["rule"]["chain"]) # family, chain # Add the rule to the priority counts. We don't need to store the # rule, just bump the ref count for the priority value. if verb == "delete": if chain not in priority_counts or \ priority not in priority_counts[chain] or \ priority_counts[chain][priority] <= 0: raise FirewallError(UNKNOWN_ERROR, "nonexistent or underflow of priority count") priority_counts[chain][priority] -= 1 else: if chain not in priority_counts: priority_counts[chain] = {} if priority not in priority_counts[chain]: priority_counts[chain][priority] = 0 # calculate index of new rule index = 0 for p in sorted(priority_counts[chain].keys()): if p == priority and verb == "insert": break index += priority_counts[chain][p] if p == priority and verb == "add": break priority_counts[chain][priority] += 1 _verb_snippet = rule[verb] del rule[verb] if index == 0: rule["insert"] = _verb_snippet else: index -= 1 # point to the rule before insertion point rule["add"] = _verb_snippet rule["add"]["rule"]["index"] = index def _get_rule_key(self, rule): for verb in ["add", "insert", "delete"]: if verb in rule and "rule" in rule[verb]: rule_key = copy.deepcopy(rule[verb]["rule"]) for non_key in ["index", "handle", "position"]: if non_key in rule_key: del rule_key[non_key] # str(rule_key) is insufficient because dictionary order is # not stable.. so abuse the JSON library rule_key = json.dumps(rule_key, sort_keys=True) return rule_key # Not a rule (it's a table, chain, etc) return None def set_rules(self, rules, log_denied): _valid_verbs = ["add", "insert", "delete", "flush", "replace"] _valid_add_verbs = ["add", "insert", "replace"] _deduplicated_rules = [] _executed_rules = [] rich_rule_priority_counts = copy.deepcopy(self.rich_rule_priority_counts) policy_priority_counts = copy.deepcopy(self.policy_priority_counts) zone_source_index_cache = copy.deepcopy(self.zone_source_index_cache) rule_ref_count = self.rule_ref_count.copy() for rule in rules: if type(rule) != dict: raise FirewallError(UNKNOWN_ERROR, "rule must be a dictionary, rule: %s" % (rule)) for verb in _valid_verbs: if verb in rule: break if verb not in rule: raise FirewallError(INVALID_RULE, "no valid verb found, rule: %s" % (rule)) rule_key = self._get_rule_key(rule) # rule deduplication if rule_key in rule_ref_count: log.debug2("%s: prev rule ref cnt %d, %s", self.__class__, rule_ref_count[rule_key], rule_key) if verb != "delete": rule_ref_count[rule_key] += 1 continue elif rule_ref_count[rule_key] > 1: rule_ref_count[rule_key] -= 1 continue elif rule_ref_count[rule_key] == 1: rule_ref_count[rule_key] -= 1 else: raise FirewallError(UNKNOWN_ERROR, "rule ref count bug: rule_key '%s', cnt %d" % (rule_key, rule_ref_count[rule_key])) elif rule_key and verb != "delete": rule_ref_count[rule_key] = 1 _deduplicated_rules.append(rule) _rule = copy.deepcopy(rule) if rule_key: # filter empty rule expressions. Rich rules add quite a bit of # them, but it makes the rest of the code simpler. libnftables # does not tolerate them. _rule[verb]["rule"]["expr"] = list(filter(None, _rule[verb]["rule"]["expr"])) self._set_rule_replace_priority(_rule, rich_rule_priority_counts, "%%RICH_RULE_PRIORITY%%") self._set_rule_replace_priority(_rule, policy_priority_counts, "%%POLICY_PRIORITY%%") self._run_replace_zone_source(_rule, zone_source_index_cache) # delete using rule handle if verb == "delete": _rule = {"delete": {"rule": {"family": _rule["delete"]["rule"]["family"], "table": _rule["delete"]["rule"]["table"], "chain": _rule["delete"]["rule"]["chain"], "handle": self.rule_to_handle[rule_key]}}} _executed_rules.append(_rule) json_blob = {"nftables": [{"metainfo": {"json_schema_version": 1}}] + _executed_rules} if log.getDebugLogLevel() >= 3: # guarded with if statement because json.dumps() is expensive. log.debug3("%s: calling python-nftables with JSON blob: %s", self.__class__, json.dumps(json_blob)) rc, output, error = self.nftables.json_cmd(json_blob) if rc != 0: raise ValueError("'%s' failed: %s\nJSON blob:\n%s" % ("python-nftables", error, json.dumps(json_blob))) self.rich_rule_priority_counts = rich_rule_priority_counts self.policy_priority_counts = policy_priority_counts self.zone_source_index_cache = zone_source_index_cache self.rule_ref_count = rule_ref_count index = 0 for rule in _deduplicated_rules: index += 1 # +1 due to metainfo rule_key = self._get_rule_key(rule) if not rule_key: continue if "delete" in rule: del self.rule_to_handle[rule_key] del self.rule_ref_count[rule_key] continue for verb in _valid_add_verbs: if verb in output["nftables"][index]: break if verb not in output["nftables"][index]: continue self.rule_to_handle[rule_key] = output["nftables"][index][verb]["rule"]["handle"] def set_rule(self, rule, log_denied): self.set_rules([rule], log_denied) return "" def get_available_tables(self, table=None): # Tables always exist in nftables return [table] if table else IPTABLES_TO_NFT_HOOK.keys() def _build_delete_table_rules(self, table): # To avoid nftables returning ENOENT we always add the table before # deleting to guarantee it will exist. # # In the future, this add+delete should be replaced with "destroy", but # that verb is too new to rely upon. rules = [] for family in ["inet", "ip", "ip6"]: rules.append({"add": {"table": {"family": family, "name": table}}}) rules.append({"delete": {"table": {"family": family, "name": table}}}) return rules def build_flush_rules(self): # Policy is stashed in a separate table that we're _not_ going to # flush. As such, we retain the policy rule handles and ref counts. saved_rule_to_handle = {} saved_rule_ref_count = {} for rule in self._build_set_policy_rules_ct_rules(True): policy_key = self._get_rule_key(rule) if policy_key in self.rule_to_handle: saved_rule_to_handle[policy_key] = self.rule_to_handle[policy_key] saved_rule_ref_count[policy_key] = self.rule_ref_count[policy_key] self.rule_to_handle = saved_rule_to_handle self.rule_ref_count = saved_rule_ref_count self.rich_rule_priority_counts = {} self.policy_priority_counts = {} self.zone_source_index_cache = {} for family in ["inet", "ip", "ip6"]: if TABLE_NAME in self.created_tables[family]: self.created_tables[family].remove(TABLE_NAME) return self._build_delete_table_rules(TABLE_NAME) def _build_set_policy_rules_ct_rules(self, enable): add_del = { True: "add", False: "delete" }[enable] rules = [] for hook in ["input", "forward", "output"]: rules.append({add_del: {"rule": {"family": "inet", "table": TABLE_NAME_POLICY, "chain": "%s_%s" % ("filter", hook), "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["established", "related"]}}}, {"accept": None}]}}}) return rules def build_set_policy_rules(self, policy): # Policy is not exposed to the user. It's only to make sure we DROP # packets while reloading and for panic mode. As such, using hooks with # a higher priority than our base chains is sufficient. rules = [] if policy == "PANIC": rules.append({"add": {"table": {"family": "inet", "name": TABLE_NAME_POLICY}}}) self.created_tables["inet"].append(TABLE_NAME_POLICY) # Use "raw" priority for panic mode. This occurs before # conntrack, mangle, nat, etc for hook in ["prerouting", "output"]: rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME_POLICY, "name": "%s_%s" % ("raw", hook), "type": "filter", "hook": hook, "prio": -300 + NFT_HOOK_OFFSET - 1, "policy": "drop"}}}) if policy == "DROP": rules.append({"add": {"table": {"family": "inet", "name": TABLE_NAME_POLICY}}}) self.created_tables["inet"].append(TABLE_NAME_POLICY) # To drop everything except existing connections we use # "filter" because it occurs _after_ conntrack. for hook in ["input", "forward", "output"]: rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME_POLICY, "name": "%s_%s" % ("filter", hook), "type": "filter", "hook": hook, "prio": 0 + NFT_HOOK_OFFSET - 1, "policy": "drop"}}}) rules += self._build_set_policy_rules_ct_rules(True) elif policy == "ACCEPT": for rule in self._build_set_policy_rules_ct_rules(False): policy_key = self._get_rule_key(rule) if policy_key in self.rule_to_handle: rules.append(rule) rules += self._build_delete_table_rules(TABLE_NAME_POLICY) if TABLE_NAME_POLICY in self.created_tables["inet"]: self.created_tables["inet"].remove(TABLE_NAME_POLICY) else: FirewallError(UNKNOWN_ERROR, "not implemented") return rules def supported_icmp_types(self, ipv=None): # nftables supports any icmp_type via arbitrary type/code matching. # We just need a translation for it in ICMP_TYPES_FRAGMENTS. supported = set() for _ipv in [ipv] if ipv else ICMP_TYPES_FRAGMENTS.keys(): supported.update(ICMP_TYPES_FRAGMENTS[_ipv].keys()) return list(supported) def build_default_tables(self): default_tables = [] for family in ["inet", "ip", "ip6"]: default_tables.append({"add": {"table": {"family": family, "name": TABLE_NAME}}}) self.created_tables[family].append(TABLE_NAME) return default_tables def build_default_rules(self, log_denied="off"): default_rules = [] for chain in IPTABLES_TO_NFT_HOOK["mangle"].keys(): default_rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME, "name": "mangle_%s" % chain, "type": "filter", "hook": "%s" % IPTABLES_TO_NFT_HOOK["mangle"][chain][0], "prio": IPTABLES_TO_NFT_HOOK["mangle"][chain][1]}}}) for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]: default_rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME, "name": "mangle_%s_%s" % (chain, dispatch_suffix)}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "mangle_%s" % chain, "expr": [{"jump": {"target": "mangle_%s_%s" % (chain, dispatch_suffix)}}]}}}) for family in ["ip", "ip6"]: for chain in IPTABLES_TO_NFT_HOOK["nat"].keys(): default_rules.append({"add": {"chain": {"family": family, "table": TABLE_NAME, "name": "nat_%s" % chain, "type": "nat", "hook": "%s" % IPTABLES_TO_NFT_HOOK["nat"][chain][0], "prio": IPTABLES_TO_NFT_HOOK["nat"][chain][1]}}}) for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]: default_rules.append({"add": {"chain": {"family": family, "table": TABLE_NAME, "name": "nat_%s_%s" % (chain, dispatch_suffix)}}}) default_rules.append({"add": {"rule": {"family": family, "table": TABLE_NAME, "chain": "nat_%s" % chain, "expr": [{"jump": {"target": "nat_%s_%s" % (chain, dispatch_suffix)}}]}}}) for chain in IPTABLES_TO_NFT_HOOK["filter"].keys(): default_rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME, "name": "filter_%s" % chain, "type": "filter", "hook": "%s" % IPTABLES_TO_NFT_HOOK["filter"][chain][0], "prio": IPTABLES_TO_NFT_HOOK["filter"][chain][1]}}}) # filter, INPUT default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "INPUT", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["established", "related"]}}}, {"accept": None}]}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "INPUT", "expr": [{"match": {"left": {"ct": {"key": "status"}}, "op": "in", "right": "dnat"}}, {"accept": None}]}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "INPUT", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "lo"}}, {"accept": None}]}}}) for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]: default_rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME, "name": "filter_%s_%s" % ("INPUT", dispatch_suffix)}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "INPUT", "expr": [{"jump": {"target": "filter_%s_%s" % ("INPUT", dispatch_suffix)}}]}}}) if log_denied != "off": default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "INPUT", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["invalid"]}}}, self._pkttype_match_fragment(log_denied), {"log": {"prefix": "STATE_INVALID_DROP: "}}]}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "INPUT", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["invalid"]}}}, {"drop": None}]}}}) if log_denied != "off": default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "INPUT", "expr": [self._pkttype_match_fragment(log_denied), {"log": {"prefix": "FINAL_REJECT: "}}]}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "INPUT", "expr": [{"reject": {"type": "icmpx", "expr": "admin-prohibited"}}]}}}) # filter, FORWARD default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "FORWARD", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["established", "related"]}}}, {"accept": None}]}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "FORWARD", "expr": [{"match": {"left": {"ct": {"key": "status"}}, "op": "in", "right": "dnat"}}, {"accept": None}]}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "FORWARD", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "lo"}}, {"accept": None}]}}}) for dispatch_suffix in ["POLICIES_pre"]: default_rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME, "name": "filter_%s_%s" % ("FORWARD", dispatch_suffix)}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "FORWARD", "expr": [{"jump": {"target": "filter_%s_%s" % ("FORWARD", dispatch_suffix)}}]}}}) for direction in ["IN", "OUT"]: for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME, "name": "filter_%s_%s_%s" % ("FORWARD", direction, dispatch_suffix)}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "FORWARD", "expr": [{"jump": {"target": "filter_%s_%s_%s" % ("FORWARD", direction, dispatch_suffix)}}]}}}) for dispatch_suffix in ["POLICIES_post"]: default_rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME, "name": "filter_%s_%s" % ("FORWARD", dispatch_suffix)}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "FORWARD", "expr": [{"jump": {"target": "filter_%s_%s" % ("FORWARD", dispatch_suffix)}}]}}}) if log_denied != "off": default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "FORWARD", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["invalid"]}}}, self._pkttype_match_fragment(log_denied), {"log": {"prefix": "STATE_INVALID_DROP: "}}]}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "FORWARD", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["invalid"]}}}, {"drop": None}]}}}) if log_denied != "off": default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "FORWARD", "expr": [self._pkttype_match_fragment(log_denied), {"log": {"prefix": "FINAL_REJECT: "}}]}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "FORWARD", "expr": [{"reject": {"type": "icmpx", "expr": "admin-prohibited"}}]}}}) # filter, OUTPUT default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "OUTPUT", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["established", "related"]}}}, {"accept": None}]}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_OUTPUT", "expr": [{"match": {"left": {"meta": {"key": "oifname"}}, "op": "==", "right": "lo"}}, {"accept": None}]}}}) for dispatch_suffix in ["POLICIES_pre"]: default_rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME, "name": "filter_%s_%s" % ("OUTPUT", dispatch_suffix)}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "OUTPUT", "expr": [{"jump": {"target": "filter_%s_%s" % ("OUTPUT", dispatch_suffix)}}]}}}) for dispatch_suffix in ["POLICIES_post"]: default_rules.append({"add": {"chain": {"family": "inet", "table": TABLE_NAME, "name": "filter_%s_%s" % ("OUTPUT", dispatch_suffix)}}}) default_rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s" % "OUTPUT", "expr": [{"jump": {"target": "filter_%s_%s" % ("OUTPUT", dispatch_suffix)}}]}}}) return default_rules def get_zone_table_chains(self, table): if table == "filter": return ["INPUT", "FORWARD_IN", "FORWARD_OUT"] if table == "mangle": return ["PREROUTING"] if table == "nat": return ["PREROUTING", "POSTROUTING"] return [] def build_policy_ingress_egress_rules(self, enable, policy, table, chain, ingress_interfaces, egress_interfaces, ingress_sources, egress_sources, family="inet"): # nat tables need to use ip/ip6 family if table == "nat" and family == "inet": rules = [] rules.extend(self.build_policy_ingress_egress_rules(enable, policy, table, chain, ingress_interfaces, egress_interfaces, ingress_sources, egress_sources, family="ip")) rules.extend(self.build_policy_ingress_egress_rules(enable, policy, table, chain, ingress_interfaces, egress_interfaces, ingress_sources, egress_sources, family="ip6")) return rules p_obj = self._fw.policy.get_policy(policy) chain_suffix = "pre" if p_obj.priority < 0 else "post" isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT) ingress_fragments = [] egress_fragments = [] if ingress_interfaces: ingress_fragments.append({"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": {"set": list(ingress_interfaces)}}}) if egress_interfaces: egress_fragments.append({"match": {"left": {"meta": {"key": "oifname"}}, "op": "==", "right": {"set": list(egress_interfaces)}}}) ipv_to_family = {"ipv4": "ip", "ipv6": "ip6"} if ingress_sources: for src in ingress_sources: # skip if this source doesn't apply to the current family. if table == "nat": ipv = self._fw.zone.check_source(src) if ipv in ipv_to_family and family != ipv_to_family[ipv]: continue ingress_fragments.append(self._rule_addr_fragment("saddr", src)) if egress_sources: for dst in egress_sources: # skip if this source doesn't apply to the current family. if table == "nat": ipv = self._fw.zone.check_source(dst) if ipv in ipv_to_family and family != ipv_to_family[ipv]: continue egress_fragments.append(self._rule_addr_fragment("daddr", dst)) def _generate_policy_dispatch_rule(ingress_fragment, egress_fragment): expr_fragments = [] if ingress_fragment: expr_fragments.append(ingress_fragment) if egress_fragment: expr_fragments.append(egress_fragment) expr_fragments.append({"jump": {"target": "%s_%s" % (table, _policy)}}) rule = {"family": family, "table": TABLE_NAME, "chain": "%s_%s_POLICIES_%s" % (table, chain, chain_suffix), "expr": expr_fragments} rule.update(self._policy_priority_fragment(p_obj)) if enable: return {"add": {"rule": rule}} else: return {"delete": {"rule": rule}} rules = [] if ingress_fragments: # zone --> [zone, ANY, HOST] for ingress_fragment in ingress_fragments: if egress_fragments: # zone --> zone for egress_fragment in egress_fragments: rules.append(_generate_policy_dispatch_rule(ingress_fragment, egress_fragment)) elif table =="nat" and egress_sources: # if the egress source is not for the current family (there # are no egress fragments), then avoid creating an invalid # catch all rule. pass else: # zone --> [ANY, HOST] rules.append(_generate_policy_dispatch_rule(ingress_fragment, None)) elif table =="nat" and ingress_sources: # if the ingress source is not for the current family (there are no # ingress fragments), then avoid creating an invalid catch all # rule. pass else: # [ANY, HOST] --> [zone, ANY, HOST] if egress_fragments: # [ANY, HOST] --> zone for egress_fragment in egress_fragments: rules.append(_generate_policy_dispatch_rule(None, egress_fragment)) elif table =="nat" and egress_sources: # if the egress source is not for the current family (there are # no egress fragments), then avoid creating an invalid catch # all rule. pass else: # [ANY, HOST] --> [ANY, HOST] rules.append(_generate_policy_dispatch_rule(None, None)) return rules def build_zone_source_interface_rules(self, enable, zone, policy, interface, table, chain, append=False, family="inet"): # nat tables needs to use ip/ip6 family if table == "nat" and family == "inet": rules = [] rules.extend(self.build_zone_source_interface_rules(enable, zone, policy, interface, table, chain, append, "ip")) rules.extend(self.build_zone_source_interface_rules(enable, zone, policy, interface, table, chain, append, "ip6")) return rules isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT) opt = { "PREROUTING": "iifname", "POSTROUTING": "oifname", "INPUT": "iifname", "FORWARD_IN": "iifname", "FORWARD_OUT": "oifname", "OUTPUT": "oifname", }[chain] if interface[len(interface)-1] == "+": interface = interface[:len(interface)-1] + "*" action = "goto" if interface == "*": expr_fragments = [{action: {"target": "%s_%s" % (table, _policy)}}] else: expr_fragments = [{"match": {"left": {"meta": {"key": opt}}, "op": "==", "right": interface}}, {action: {"target": "%s_%s" % (table, _policy)}}] if enable and not append: verb = "insert" rule = {"family": family, "table": TABLE_NAME, "chain": "%s_%s_ZONES" % (table, chain), "expr": expr_fragments} rule.update(self._zone_interface_fragment()) elif enable: verb = "add" rule = {"family": family, "table": TABLE_NAME, "chain": "%s_%s_ZONES" % (table, chain), "expr": expr_fragments} else: verb = "delete" rule = {"family": family, "table": TABLE_NAME, "chain": "%s_%s_ZONES" % (table, chain), "expr": expr_fragments} if not append: rule.update(self._zone_interface_fragment()) return [{verb: {"rule": rule}}] def build_zone_source_address_rules(self, enable, zone, policy, address, table, chain, family="inet"): # nat tables needs to use ip/ip6 family if table == "nat" and family == "inet": rules = [] if address.startswith("ipset:"): ipset_family = self._set_get_family(address[len("ipset:"):]) else: ipset_family = None if check_address("ipv4", address) or check_mac(address) or ipset_family == "ip": rules.extend(self.build_zone_source_address_rules(enable, zone, policy, address, table, chain, "ip")) if check_address("ipv6", address) or check_mac(address) or ipset_family == "ip6": rules.extend(self.build_zone_source_address_rules(enable, zone, policy, address, table, chain, "ip6")) return rules isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT) add_del = { True: "insert", False: "delete" }[enable] opt = { "PREROUTING": "saddr", "POSTROUTING": "daddr", "INPUT": "saddr", "FORWARD_IN": "saddr", "FORWARD_OUT": "daddr", "OUTPUT": "daddr", }[chain] if self._fw._allow_zone_drifting: zone_dispatch_chain = "%s_%s_ZONES_SOURCE" % (table, chain) else: zone_dispatch_chain = "%s_%s_ZONES" % (table, chain) action = "goto" rule = {"family": family, "table": TABLE_NAME, "chain": zone_dispatch_chain, "expr": [self._rule_addr_fragment(opt, address), {action: {"target": "%s_%s" % (table, _policy)}}]} rule.update(self._zone_source_fragment(zone, address)) return [{add_del: {"rule": rule}}] def build_policy_chain_rules(self, enable, policy, table, chain, family="inet"): # nat tables needs to use ip/ip6 family if table == "nat" and family == "inet": rules = [] rules.extend(self.build_policy_chain_rules(enable, policy, table, chain, "ip")) rules.extend(self.build_policy_chain_rules(enable, policy, table, chain, "ip6")) return rules add_del = { True: "add", False: "delete" }[enable] isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT) rules = [] rules.append({add_del: {"chain": {"family": family, "table": TABLE_NAME, "name": "%s_%s" % (table, _policy)}}}) for chain_suffix in ["pre", "log", "deny", "allow", "post"]: rules.append({add_del: {"chain": {"family": family, "table": TABLE_NAME, "name": "%s_%s_%s" % (table, _policy, chain_suffix)}}}) for chain_suffix in ["pre", "log", "deny", "allow", "post"]: rules.append({add_del: {"rule": {"family": family, "table": TABLE_NAME, "chain": "%s_%s" % (table, _policy), "expr": [{"jump": {"target": "%s_%s_%s" % (table, _policy, chain_suffix)}}]}}}) target = self._fw.policy._policies[policy].target if self._fw.get_log_denied() != "off": if table == "filter": if target in ["REJECT", "%%REJECT%%", "DROP"]: log_suffix = target if target == "%%REJECT%%": log_suffix = "REJECT" rules.append({add_del: {"rule": {"family": family, "table": TABLE_NAME, "chain": "%s_%s" % (table, _policy), "expr": [self._pkttype_match_fragment(self._fw.get_log_denied()), {"log": {"prefix": "\"filter_%s_%s: \"" % (_policy, log_suffix)}}]}}}) if table == "filter" and \ target in ["ACCEPT", "REJECT", "%%REJECT%%", "DROP"]: if target in ["%%REJECT%%", "REJECT"]: target_fragment = self._reject_fragment() else: target_fragment = {target.lower(): None} rules.append({add_del: {"rule": {"family": family, "table": TABLE_NAME, "chain": "%s_%s" % (table, _policy), "expr": [target_fragment]}}}) if not enable: rules.reverse() return rules def _pkttype_match_fragment(self, pkttype): if pkttype == "all": return {} elif pkttype in ["unicast", "broadcast", "multicast"]: return {"match": {"left": {"meta": {"key": "pkttype"}}, "op": "==", "right": pkttype}} raise FirewallError(INVALID_RULE, "Invalid pkttype \"%s\"", pkttype) def _reject_types_fragment(self, reject_type): frags = { # REJECT_TYPES : "icmp-host-prohibited" : {"reject": {"type": "icmp", "expr": "host-prohibited"}}, "host-prohib" : {"reject": {"type": "icmp", "expr": "host-prohibited"}}, "icmp-net-prohibited" : {"reject": {"type": "icmp", "expr": "net-prohibited"}}, "net-prohib" : {"reject": {"type": "icmp", "expr": "net-prohibited"}}, "icmp-admin-prohibited" : {"reject": {"type": "icmp", "expr": "admin-prohibited"}}, "admin-prohib" : {"reject": {"type": "icmp", "expr": "admin-prohibited"}}, "icmp6-adm-prohibited" : {"reject": {"type": "icmpv6", "expr": "admin-prohibited"}}, "adm-prohibited" : {"reject": {"type": "icmpv6", "expr": "admin-prohibited"}}, "icmp-net-unreachable" : {"reject": {"type": "icmp", "expr": "net-unreachable"}}, "net-unreach" : {"reject": {"type": "icmp", "expr": "net-unreachable"}}, "icmp-host-unreachable" : {"reject": {"type": "icmp", "expr": "host-unreachable"}}, "host-unreach" : {"reject": {"type": "icmp", "expr": "host-unreachable"}}, "icmp-port-unreachable" : {"reject": {"type": "icmp", "expr": "port-unreachable"}}, "icmp6-port-unreachable" : {"reject": {"type": "icmpv6", "expr": "port-unreachable"}}, "port-unreach" : {"reject": {"type": "icmpx", "expr": "port-unreachable"}}, "icmp-proto-unreachable" : {"reject": {"type": "icmp", "expr": "prot-unreachable"}}, "proto-unreach" : {"reject": {"type": "icmp", "expr": "prot-unreachable"}}, "icmp6-addr-unreachable" : {"reject": {"type": "icmpv6", "expr": "addr-unreachable"}}, "addr-unreach" : {"reject": {"type": "icmpv6", "expr": "addr-unreachable"}}, "icmp6-no-route" : {"reject": {"type": "icmpv6", "expr": "no-route"}}, "no-route" : {"reject": {"type": "icmpv6", "expr": "no-route"}}, "tcp-reset" : {"reject": {"type": "tcp reset"}}, "tcp-rst" : {"reject": {"type": "tcp reset"}}, } return frags[reject_type] def _reject_fragment(self): return {"reject": {"type": "icmpx", "expr": "admin-prohibited"}} def _icmp_match_fragment(self): return {"match": {"left": {"meta": {"key": "l4proto"}}, "op": "==", "right": {"set": ["icmp", "icmpv6"]}}} def _rich_rule_limit_fragment(self, limit): if not limit: return {} rich_to_nft = { "s" : "second", "m" : "minute", "h" : "hour", "d" : "day", } rate, duration = limit.value_parse() d = { "rate": rate, "per": rich_to_nft[duration], } burst = limit.burst_parse() if burst is not None: d["burst"] = burst return {"limit": d} def _rich_rule_chain_suffix(self, rich_rule): if type(rich_rule.element) in [Rich_Masquerade, Rich_ForwardPort, Rich_IcmpBlock]: # These are special and don't have an explicit action pass elif rich_rule.action: if type(rich_rule.action) not in [Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark]: raise FirewallError(INVALID_RULE, "Unknown action %s" % type(rich_rule.action)) else: raise FirewallError(INVALID_RULE, "No rule action specified.") if rich_rule.priority == 0: if type(rich_rule.element) in [Rich_Masquerade, Rich_ForwardPort] or \ type(rich_rule.action) in [Rich_Accept, Rich_Mark]: return "allow" elif type(rich_rule.element) in [Rich_IcmpBlock] or \ type(rich_rule.action) in [Rich_Reject, Rich_Drop]: return "deny" elif rich_rule.priority < 0: return "pre" else: return "post" def _rich_rule_chain_suffix_from_log(self, rich_rule): if not rich_rule.log and not rich_rule.audit: raise FirewallError(INVALID_RULE, "Not log or audit") if rich_rule.priority == 0: return "log" elif rich_rule.priority < 0: return "pre" else: return "post" def _zone_interface_fragment(self): return {"%%ZONE_INTERFACE%%": None} def _zone_source_fragment(self, zone, address): if check_single_address("ipv6", address): address = normalizeIP6(address) elif check_address("ipv6", address): addr_split = address.split("/") address = normalizeIP6(addr_split[0]) + "/" + addr_split[1] return {"%%ZONE_SOURCE%%": {"zone": zone, "address": address}} def _policy_priority_fragment(self, policy): return {"%%POLICY_PRIORITY%%": policy.priority} def _rich_rule_priority_fragment(self, rich_rule): if not rich_rule or rich_rule.priority == 0: return {} return {"%%RICH_RULE_PRIORITY%%": rich_rule.priority} def _rich_rule_log(self, policy, rich_rule, enable, table, expr_fragments): if not rich_rule.log: return {} _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "add", False: "delete" }[enable] chain_suffix = self._rich_rule_chain_suffix_from_log(rich_rule) log_options = {} if rich_rule.log.prefix: log_options["prefix"] = "%s" % rich_rule.log.prefix if rich_rule.log.level: level = "warn" if "warning" == rich_rule.log.level else rich_rule.log.level log_options["level"] = "%s" % level rule = {"family": "inet", "table": TABLE_NAME, "chain": "%s_%s_%s" % (table, _policy, chain_suffix), "expr": expr_fragments + [self._rich_rule_limit_fragment(rich_rule.log.limit), {"log": log_options}]} rule.update(self._rich_rule_priority_fragment(rich_rule)) return {add_del: {"rule": rule}} def _rich_rule_audit(self, policy, rich_rule, enable, table, expr_fragments): if not rich_rule.audit: return {} _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "add", False: "delete" }[enable] chain_suffix = self._rich_rule_chain_suffix_from_log(rich_rule) rule = {"family": "inet", "table": TABLE_NAME, "chain": "%s_%s_%s" % (table, _policy, chain_suffix), "expr": expr_fragments + [self._rich_rule_limit_fragment(rich_rule.audit.limit), {"log": {"level": "audit"}}]} rule.update(self._rich_rule_priority_fragment(rich_rule)) return {add_del: {"rule": rule}} def _rich_rule_action(self, policy, rich_rule, enable, table, expr_fragments): if not rich_rule.action: return {} _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "add", False: "delete" }[enable] chain_suffix = self._rich_rule_chain_suffix(rich_rule) chain = "%s_%s_%s" % (table, _policy, chain_suffix) if type(rich_rule.action) == Rich_Accept: rule_action = {"accept": None} elif type(rich_rule.action) == Rich_Reject: if rich_rule.action.type: rule_action = self._reject_types_fragment(rich_rule.action.type) else: rule_action = {"reject": None} elif type(rich_rule.action) == Rich_Drop: rule_action = {"drop": None} elif type(rich_rule.action) == Rich_Mark: table = "mangle" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) chain = "%s_%s_%s" % (table, _policy, chain_suffix) value = rich_rule.action.set.split("/") if len(value) > 1: rule_action = {"mangle": {"key": {"meta": {"key": "mark"}}, "value": {"^": [{"&": [{"meta": {"key": "mark"}}, value[1]]}, value[0]]}}} else: rule_action = {"mangle": {"key": {"meta": {"key": "mark"}}, "value": value[0]}} else: raise FirewallError(INVALID_RULE, "Unknown action %s" % type(rich_rule.action)) rule = {"family": "inet", "table": TABLE_NAME, "chain": chain, "expr": expr_fragments + [self._rich_rule_limit_fragment(rich_rule.action.limit), rule_action]} rule.update(self._rich_rule_priority_fragment(rich_rule)) return {add_del: {"rule": rule}} def _rule_addr_fragment(self, addr_field, address, invert=False): if address.startswith("ipset:"): return self._set_match_fragment(address[len("ipset:"):], True if "daddr" == addr_field else False, invert) else: if check_mac(address): family = "ether" elif check_single_address("ipv4", address): family = "ip" elif check_address("ipv4", address): family = "ip" normalized_address = ipaddress.IPv4Network(address, strict=False) address = {"prefix": {"addr": normalized_address.network_address.compressed, "len": normalized_address.prefixlen}} elif check_single_address("ipv6", address): family = "ip6" address = normalizeIP6(address) else: family = "ip6" addr_len = address.split("/") address = {"prefix": {"addr": normalizeIP6(addr_len[0]), "len": int(addr_len[1])}} return {"match": {"left": {"payload": {"protocol": family, "field": addr_field}}, "op": "!=" if invert else "==", "right": address}} def _rich_rule_family_fragment(self, rich_family): if not rich_family: return {} if rich_family not in ["ipv4", "ipv6"]: raise FirewallError(INVALID_RULE, "Invalid family" % rich_family) return {"match": {"left": {"meta": {"key": "nfproto"}}, "op": "==", "right": rich_family}} def _rich_rule_destination_fragment(self, rich_dest): if not rich_dest: return {} if rich_dest.addr: address = rich_dest.addr elif rich_dest.ipset: address = "ipset:" + rich_dest.ipset return self._rule_addr_fragment("daddr", address, invert=rich_dest.invert) def _rich_rule_source_fragment(self, rich_source): if not rich_source: return {} if rich_source.addr: address = rich_source.addr elif hasattr(rich_source, "mac") and rich_source.mac: address = rich_source.mac elif hasattr(rich_source, "ipset") and rich_source.ipset: address = "ipset:" + rich_source.ipset return self._rule_addr_fragment("saddr", address, invert=rich_source.invert) def _port_fragment(self, port): range = getPortRange(port) if isinstance(range, int) and range < 0: raise FirewallError(INVALID_PORT) elif len(range) == 1: return range[0] else: return {"range": [range[0], range[1]]} def build_policy_ports_rules(self, enable, policy, proto, port, destination=None, rich_rule=None): add_del = { True: "add", False: "delete" }[enable] table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) expr_fragments = [] if rich_rule: expr_fragments.append(self._rich_rule_family_fragment(rich_rule.family)) if destination: expr_fragments.append(self._rule_addr_fragment("daddr", destination)) if rich_rule: expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination)) expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source)) expr_fragments.append({"match": {"left": {"payload": {"protocol": proto, "field": "dport"}}, "op": "==", "right": self._port_fragment(port)}}) if not rich_rule or type(rich_rule.action) != Rich_Mark: expr_fragments.append({"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["new", "untracked"]}}}) rules = [] if rich_rule: rules.append(self._rich_rule_log(policy, rich_rule, enable, table, expr_fragments)) rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, expr_fragments)) rules.append(self._rich_rule_action(policy, rich_rule, enable, table, expr_fragments)) else: rules.append({add_del: {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "%s_%s_allow" % (table, _policy), "expr": expr_fragments + [{"accept": None}]}}}) return rules def build_policy_protocol_rules(self, enable, policy, protocol, destination=None, rich_rule=None): add_del = { True: "add", False: "delete" }[enable] table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) expr_fragments = [] if rich_rule: expr_fragments.append(self._rich_rule_family_fragment(rich_rule.family)) if destination: expr_fragments.append(self._rule_addr_fragment("daddr", destination)) if rich_rule: expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination)) expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source)) expr_fragments.append({"match": {"left": {"meta": {"key": "l4proto"}}, "op": "==", "right": protocol}}) if not rich_rule or type(rich_rule.action) != Rich_Mark: expr_fragments.append({"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["new", "untracked"]}}}) rules = [] if rich_rule: rules.append(self._rich_rule_log(policy, rich_rule, enable, table, expr_fragments)) rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, expr_fragments)) rules.append(self._rich_rule_action(policy, rich_rule, enable, table, expr_fragments)) else: rules.append({add_del: {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "%s_%s_allow" % (table, _policy), "expr": expr_fragments + [{"accept": None}]}}}) return rules def build_policy_source_ports_rules(self, enable, policy, proto, port, destination=None, rich_rule=None): add_del = { True: "add", False: "delete" }[enable] table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) expr_fragments = [] if rich_rule: expr_fragments.append(self._rich_rule_family_fragment(rich_rule.family)) if destination: expr_fragments.append(self._rule_addr_fragment("daddr", destination)) if rich_rule: expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination)) expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source)) expr_fragments.append({"match": {"left": {"payload": {"protocol": proto, "field": "sport"}}, "op": "==", "right": self._port_fragment(port)}}) if not rich_rule or type(rich_rule.action) != Rich_Mark: expr_fragments.append({"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["new", "untracked"]}}}) rules = [] if rich_rule: rules.append(self._rich_rule_log(policy, rich_rule, enable, table, expr_fragments)) rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, expr_fragments)) rules.append(self._rich_rule_action(policy, rich_rule, enable, table, expr_fragments)) else: rules.append({add_del: {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "%s_%s_allow" % (table, _policy), "expr": expr_fragments + [{"accept": None}]}}}) return rules def build_policy_helper_ports_rules(self, enable, policy, proto, port, destination, helper_name, module_short_name): table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "add", False: "delete" }[enable] rules = [] if enable: rules.append({"add": {"ct helper": {"family": "inet", "table": TABLE_NAME, "name": "helper-%s-%s" % (helper_name, proto), "type": module_short_name, "protocol": proto}}}) expr_fragments = [] if destination: expr_fragments.append(self._rule_addr_fragment("daddr", destination)) expr_fragments.append({"match": {"left": {"payload": {"protocol": proto, "field": "dport"}}, "op": "==", "right": self._port_fragment(port)}}) expr_fragments.append({"ct helper": "helper-%s-%s" % (helper_name, proto)}) rules.append({add_del: {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s_allow" % (_policy), "expr": expr_fragments}}}) return rules def build_zone_forward_rules(self, enable, zone, policy, table, interface=None, source=None): add_del = { True: "add", False: "delete" }[enable] _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) rules = [] if interface: if interface[len(interface)-1] == "+": interface = interface[:len(interface)-1] + "*" expr = [{"match": {"left": {"meta": {"key": "oifname"}}, "op": "==", "right": interface}}, {"accept": None}] else: # source expr = [self._rule_addr_fragment("daddr", source), {"accept": None}] rule = {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s_allow" % (_policy), "expr": expr} rules.append({add_del: {"rule": rule}}) return rules def _build_policy_masquerade_nat_rules(self, enable, policy, family, rich_rule=None): table = "nat" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=True) add_del = { True: "add", False: "delete" }[enable] expr_fragments = [] if rich_rule: expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination)) expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source)) chain_suffix = self._rich_rule_chain_suffix(rich_rule) else: chain_suffix = "allow" rule = {"family": family, "table": TABLE_NAME, "chain": "nat_%s_%s" % (_policy, chain_suffix), "expr": expr_fragments + [{"match": {"left": {"meta": {"key": "oifname"}}, "op": "!=", "right": "lo"}}, {"masquerade": None}]} rule.update(self._rich_rule_priority_fragment(rich_rule)) return [{add_del: {"rule": rule}}] def build_policy_masquerade_rules(self, enable, policy, rich_rule=None): # nat tables needs to use ip/ip6 family rules = [] if rich_rule and (rich_rule.family and rich_rule.family == "ipv6" or rich_rule.source and check_address("ipv6", rich_rule.source.addr)): rules.extend(self._build_policy_masquerade_nat_rules(enable, policy, "ip6", rich_rule)) elif rich_rule and (rich_rule.family and rich_rule.family == "ipv4" or rich_rule.source and check_address("ipv4", rich_rule.source.addr)): rules.extend(self._build_policy_masquerade_nat_rules(enable, policy, "ip", rich_rule)) else: rules.extend(self._build_policy_masquerade_nat_rules(enable, policy, "ip", rich_rule)) table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "add", False: "delete" }[enable] expr_fragments = [] if rich_rule: expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination)) expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source)) chain_suffix = self._rich_rule_chain_suffix(rich_rule) else: chain_suffix = "allow" rule = {"family": "inet", "table": TABLE_NAME, "chain": "filter_%s_%s" % (_policy, chain_suffix), "expr": expr_fragments + [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["new", "untracked"]}}}, {"accept": None}]} rule.update(self._rich_rule_priority_fragment(rich_rule)) rules.append({add_del: {"rule": rule}}) return rules def _build_policy_forward_port_nat_rules(self, enable, policy, port, protocol, toaddr, toport, family, rich_rule=None): table = "nat" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "add", False: "delete" }[enable] expr_fragments = [] if rich_rule: expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination)) expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source)) chain_suffix = self._rich_rule_chain_suffix(rich_rule) else: chain_suffix = "allow" expr_fragments.append({"match": {"left": {"payload": {"protocol": protocol, "field": "dport"}}, "op": "==", "right": self._port_fragment(port)}}) if toaddr: if check_single_address("ipv6", toaddr): toaddr = normalizeIP6(toaddr) if toport and toport != "": expr_fragments.append({"dnat": {"addr": toaddr, "port": self._port_fragment(toport)}}) else: expr_fragments.append({"dnat": {"addr": toaddr}}) else: expr_fragments.append({"redirect": {"port": self._port_fragment(toport)}}) rule = {"family": family, "table": TABLE_NAME, "chain": "nat_%s_%s" % (_policy, chain_suffix), "expr": expr_fragments} rule.update(self._rich_rule_priority_fragment(rich_rule)) return [{add_del: {"rule": rule}}] def build_policy_forward_port_rules(self, enable, policy, port, protocol, toport, toaddr, rich_rule=None): rules = [] if rich_rule and (rich_rule.family and rich_rule.family == "ipv6" or toaddr and check_single_address("ipv6", toaddr)): rules.extend(self._build_policy_forward_port_nat_rules(enable, policy, port, protocol, toaddr, toport, "ip6", rich_rule)) elif rich_rule and (rich_rule.family and rich_rule.family == "ipv4" or toaddr and check_single_address("ipv4", toaddr)): rules.extend(self._build_policy_forward_port_nat_rules(enable, policy, port, protocol, toaddr, toport, "ip", rich_rule)) else: if toaddr and check_single_address("ipv6", toaddr): rules.extend(self._build_policy_forward_port_nat_rules(enable, policy, port, protocol, toaddr, toport, "ip6", rich_rule)) else: rules.extend(self._build_policy_forward_port_nat_rules(enable, policy, port, protocol, toaddr, toport, "ip", rich_rule)) return rules def _icmp_types_to_nft_fragments(self, ipv, icmp_type): if icmp_type in ICMP_TYPES_FRAGMENTS[ipv]: return ICMP_TYPES_FRAGMENTS[ipv][icmp_type] else: raise FirewallError(INVALID_ICMPTYPE, "ICMP type '%s' not supported by %s for %s" % (icmp_type, self.name, ipv)) def build_policy_icmp_block_rules(self, enable, policy, ict, rich_rule=None): table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "add", False: "delete" }[enable] if rich_rule and rich_rule.ipvs: ipvs = rich_rule.ipvs elif ict.destination: ipvs = [] if "ipv4" in ict.destination: ipvs.append("ipv4") if "ipv6" in ict.destination: ipvs.append("ipv6") else: ipvs = ["ipv4", "ipv6"] rules = [] for ipv in ipvs: if self._fw.policy.query_icmp_block_inversion(policy): final_chain = "%s_%s_allow" % (table, _policy) target_fragment = {"accept": None} else: final_chain = "%s_%s_deny" % (table, _policy) target_fragment = self._reject_fragment() expr_fragments = [] if rich_rule: expr_fragments.append(self._rich_rule_family_fragment(rich_rule.family)) expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination)) expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source)) expr_fragments.extend(self._icmp_types_to_nft_fragments(ipv, ict.name)) if rich_rule: rules.append(self._rich_rule_log(policy, rich_rule, enable, table, expr_fragments)) rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, expr_fragments)) if rich_rule.action: rules.append(self._rich_rule_action(policy, rich_rule, enable, table, expr_fragments)) else: chain_suffix = self._rich_rule_chain_suffix(rich_rule) rule = {"family": "inet", "table": TABLE_NAME, "chain": "%s_%s_%s" % (table, _policy, chain_suffix), "expr": expr_fragments + [self._reject_fragment()]} rule.update(self._rich_rule_priority_fragment(rich_rule)) rules.append({add_del: {"rule": rule}}) else: if self._fw.get_log_denied() != "off" and not self._fw.policy.query_icmp_block_inversion(policy): rules.append({add_del: {"rule": {"family": "inet", "table": TABLE_NAME, "chain": final_chain, "expr": (expr_fragments + [self._pkttype_match_fragment(self._fw.get_log_denied()), {"log": {"prefix": "\"%s_%s_ICMP_BLOCK: \"" % (table, policy)}}])}}}) rules.append({add_del: {"rule": {"family": "inet", "table": TABLE_NAME, "chain": final_chain, "expr": expr_fragments + [target_fragment]}}}) return rules def build_policy_icmp_block_inversion_rules(self, enable, policy): table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) rules = [] add_del = { True: "add", False: "delete" }[enable] if self._fw.policy.query_icmp_block_inversion(policy): target_fragment = self._reject_fragment() else: target_fragment = {"accept": None} # WARN: The "index" used here must be kept in sync with # build_policy_chain_rules() # rules.append({add_del: {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "%s_%s" % (table, _policy), "index": 4, "expr": [self._icmp_match_fragment(), target_fragment]}}}) if self._fw.get_log_denied() != "off" and self._fw.policy.query_icmp_block_inversion(policy): rules.append({add_del: {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "%s_%s" % (table, _policy), "index": 4, "expr": [self._icmp_match_fragment(), self._pkttype_match_fragment(self._fw.get_log_denied()), {"log": {"prefix": "%s_%s_ICMP_BLOCK: " % (table, policy)}}]}}}) return rules def build_rpfilter_rules(self, log_denied=False): rules = [] expr_fragments = [{"match": {"left": {"meta": {"key": "nfproto"}}, "op": "==", "right": "ipv6"}}, {"match": {"left": {"fib": {"flags": ["saddr", "iif", "mark"], "result": "oif"}}, "op": "==", "right": False}}] if log_denied != "off": expr_fragments.append({"log": {"prefix": "rpfilter_DROP: "}}) expr_fragments.append({"drop": None}) rules.append({"insert": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_PREROUTING", "expr": expr_fragments}}}) # RHBZ#1058505, RHBZ#1575431 (bug in kernel 4.16-4.17) rules.append({"insert": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_PREROUTING", "expr": [{"match": {"left": {"payload": {"protocol": "icmpv6", "field": "type"}}, "op": "==", "right": {"set": ["nd-router-advert", "nd-neighbor-solicit"]}}}, {"accept": None}]}}}) return rules def build_rfc3964_ipv4_rules(self): daddr_set = ["::0.0.0.0/96", # IPv4 compatible "::ffff:0.0.0.0/96", # IPv4 mapped "2002:0000::/24", # 0.0.0.0/8 (the system has no address assigned yet) "2002:0a00::/24", # 10.0.0.0/8 (private) "2002:7f00::/24", # 127.0.0.0/8 (loopback) "2002:ac10::/28", # 172.16.0.0/12 (private) "2002:c0a8::/32", # 192.168.0.0/16 (private) "2002:a9fe::/32", # 169.254.0.0/16 (IANA Assigned DHCP link-local) "2002:e000::/19", # 224.0.0.0/4 (multicast), 240.0.0.0/4 (reserved and broadcast) ] daddr_set = [{"prefix": {"addr": x.split("/")[0], "len": int(x.split("/")[1])}} for x in daddr_set] expr_fragments = [{"match": {"left": {"payload": {"protocol": "ip6", "field": "daddr"}}, "op": "==", "right": {"set": daddr_set}}}] if self._fw._log_denied in ["unicast", "all"]: expr_fragments.append({"log": {"prefix": "RFC3964_IPv4_REJECT: "}}) expr_fragments.append(self._reject_types_fragment("addr-unreach")) rules = [] # WARN: index must be kept in sync with build_default_rules() rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_OUTPUT", "index": 1, "expr": expr_fragments}}}) rules.append({"add": {"rule": {"family": "inet", "table": TABLE_NAME, "chain": "filter_FORWARD", "index": 2, "expr": expr_fragments}}}) return rules def build_policy_rich_source_destination_rules(self, enable, policy, rich_rule): table = "filter" expr_fragments = [] expr_fragments.append(self._rich_rule_family_fragment(rich_rule.family)) expr_fragments.append(self._rich_rule_destination_fragment(rich_rule.destination)) expr_fragments.append(self._rich_rule_source_fragment(rich_rule.source)) rules = [] rules.append(self._rich_rule_log(policy, rich_rule, enable, table, expr_fragments)) rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, expr_fragments)) rules.append(self._rich_rule_action(policy, rich_rule, enable, table, expr_fragments)) return rules def is_ipv_supported(self, ipv): if ipv in ["ipv4", "ipv6", "eb"]: return True return False def _set_type_list(self, ipv, type): ipv_addr = { "ipv4" : "ipv4_addr", "ipv6" : "ipv6_addr", } types = { "hash:ip" : ipv_addr[ipv], "hash:ip,port" : [ipv_addr[ipv], "inet_proto", "inet_service"], "hash:ip,port,ip" : [ipv_addr[ipv], "inet_proto", "inet_service", ipv_addr[ipv]], "hash:ip,port,net" : [ipv_addr[ipv], "inet_proto", "inet_service", ipv_addr[ipv]], "hash:ip,mark" : [ipv_addr[ipv], "mark"], "hash:net" : ipv_addr[ipv], "hash:net,net" : [ipv_addr[ipv], ipv_addr[ipv]], "hash:net,port" : [ipv_addr[ipv], "inet_proto", "inet_service"], "hash:net,port,net" : [ipv_addr[ipv], "inet_proto", "inet_service", ipv_addr[ipv]], "hash:net,iface" : [ipv_addr[ipv], "ifname"], "hash:mac" : "ether_addr", } if type in types: return types[type] else: raise FirewallError(INVALID_TYPE, "ipset type name '%s' is not valid" % type) def build_set_create_rules(self, name, type, options=None): if options and "family" in options and options["family"] == "inet6": ipv = "ipv6" else: ipv = "ipv4" set_dict = {"table": TABLE_NAME, "name": name, "type": self._set_type_list(ipv, type)} # Some types need the interval flag for t in type.split(":")[1].split(","): if t in ["ip", "net", "port"]: set_dict["flags"] = ["interval"] break if options: if "timeout" in options: set_dict["timeout"] = options["timeout"] if "maxelem" in options: set_dict["size"] = options["maxelem"] rules = [] for family in ["inet", "ip", "ip6"]: rule_dict = {"family": family} rule_dict.update(set_dict) rules.append({"add": {"set": rule_dict}}) return rules def set_create(self, name, type, options=None): rules = self.build_set_create_rules(name, type, options) self.set_rules(rules, self._fw.get_log_denied()) def set_destroy(self, name): for family in ["inet", "ip", "ip6"]: rule = {"delete": {"set": {"family": family, "table": TABLE_NAME, "name": name}}} self.set_rule(rule, self._fw.get_log_denied()) def _set_match_fragment(self, name, match_dest, invert=False): type_format = self._fw.ipset.get_ipset(name).type.split(":")[1].split(",") fragments = [] for i in range(len(type_format)): if type_format[i] == "port": fragments.append({"meta": {"key": "l4proto"}}) fragments.append({"payload": {"protocol": "th", "field": "dport" if match_dest else "sport"}}) elif type_format[i] in ["ip", "net", "mac"]: fragments.append({"payload": {"protocol": self._set_get_family(name), "field": "daddr" if match_dest else "saddr"}}) elif type_format[i] == "iface": fragments.append({"meta": {"key": "iifname" if match_dest else "oifname"}}) elif type_format[i] == "mark": fragments.append({"meta": {"key": "mark"}}) else: raise FirewallError("Unsupported ipset type for match fragment: %s" % (type_format[i])) return {"match": {"left": {"concat": fragments} if len(type_format) > 1 else fragments[0], "op": "!=" if invert else "==", "right": "@" + name}} def _set_entry_fragment(self, name, entry): # convert something like # 1.2.3.4,sctp:8080 (type hash:ip,port) # to # ["1.2.3.4", "sctp", "8080"] obj = self._fw.ipset.get_ipset(name) type_format = obj.type.split(":")[1].split(",") entry_tokens = entry.split(",") if len(type_format) != len(entry_tokens): raise FirewallError(INVALID_ENTRY, "Number of values does not match ipset type.") fragment = [] for i in range(len(type_format)): if type_format[i] == "port": try: index = entry_tokens[i].index(":") except ValueError: # no protocol means default tcp fragment.append("tcp") port_str = entry_tokens[i] else: fragment.append(entry_tokens[i][:index]) port_str = entry_tokens[i][index+1:] try: index = port_str.index("-") except ValueError: fragment.append(port_str) else: fragment.append({"range": [port_str[:index], port_str[index+1:]]}) elif type_format[i] in ["ip", "net"]: if '-' in entry_tokens[i]: fragment.append({"range": entry_tokens[i].split('-') }) else: try: index = entry_tokens[i].index("/") except ValueError: addr = entry_tokens[i] if "family" in obj.options and obj.options["family"] == "inet6": addr = normalizeIP6(addr) fragment.append(addr) else: addr = entry_tokens[i][:index] if "family" in obj.options and obj.options["family"] == "inet6": addr = normalizeIP6(addr) fragment.append({"prefix": {"addr": addr, "len": int(entry_tokens[i][index+1:])}}) else: fragment.append(entry_tokens[i]) return [{"concat": fragment}] if len(type_format) > 1 else fragment def build_set_add_rules(self, name, entry): rules = [] element = self._set_entry_fragment(name, entry) for family in ["inet", "ip", "ip6"]: rules.append({"add": {"element": {"family": family, "table": TABLE_NAME, "name": name, "elem": element}}}) return rules def set_add(self, name, entry): rules = self.build_set_add_rules(name, entry) self.set_rules(rules, self._fw.get_log_denied()) def set_delete(self, name, entry): element = self._set_entry_fragment(name, entry) for family in ["inet", "ip", "ip6"]: rule = {"delete": {"element": {"family": family, "table": TABLE_NAME, "name": name, "elem": element}}} self.set_rule(rule, self._fw.get_log_denied()) def build_set_flush_rules(self, name): rules = [] for family in ["inet", "ip", "ip6"]: rule = {"flush": {"set": {"family": family, "table": TABLE_NAME, "name": name}}} rules.append(rule) return rules def set_flush(self, name): rules = self.build_set_flush_rules(name) self.set_rules(rules, self._fw.get_log_denied()) def _set_get_family(self, name): ipset = self._fw.ipset.get_ipset(name) if ipset.type == "hash:mac": family = "ether" elif ipset.options and "family" in ipset.options \ and ipset.options["family"] == "inet6": family = "ip6" else: family = "ip" return family def set_restore(self, set_name, type_name, entries, create_options=None, entry_options=None): rules = [] rules.extend(self.build_set_create_rules(set_name, type_name, create_options)) rules.extend(self.build_set_flush_rules(set_name)) # avoid large memory usage by chunking the entries chunk = 0 for entry in entries: rules.extend(self.build_set_add_rules(set_name, entry)) chunk += 1 if chunk >= 1000: self.set_rules(rules, self._fw.get_log_denied()) rules.clear() chunk = 0 else: self.set_rules(rules, self._fw.get_log_denied()) PKpge[4C88rich.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2013-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "Rich_Source", "Rich_Destination", "Rich_Service", "Rich_Port", "Rich_Protocol", "Rich_Masquerade", "Rich_IcmpBlock", "Rich_IcmpType", "Rich_SourcePort", "Rich_ForwardPort", "Rich_Log", "Rich_Audit", "Rich_Accept", "Rich_Reject", "Rich_Drop", "Rich_Mark", "Rich_Limit", "Rich_Rule" ] from firewall import functions from firewall.core.ipset import check_ipset_name from firewall.core.base import REJECT_TYPES from firewall import errors from firewall.errors import FirewallError class Rich_Source(object): def __init__(self, addr, mac, ipset, invert=False): self.addr = addr if self.addr == "": self.addr = None self.mac = mac if self.mac == "" or self.mac is None: self.mac = None elif self.mac is not None: self.mac = self.mac.upper() self.ipset = ipset if self.ipset == "": self.ipset = None self.invert = invert if self.addr is None and self.mac is None and self.ipset is None: raise FirewallError(errors.INVALID_RULE, "no address, mac and ipset") def __str__(self): ret = 'source%s ' % (" NOT" if self.invert else "") if self.addr is not None: return ret + 'address="%s"' % self.addr elif self.mac is not None: return ret + 'mac="%s"' % self.mac elif self.ipset is not None: return ret + 'ipset="%s"' % self.ipset else: raise FirewallError(errors.INVALID_RULE, "no address, mac and ipset") class Rich_Destination(object): def __init__(self, addr, ipset, invert=False): self.addr = addr if self.addr == "": self.addr = None self.ipset = ipset if self.ipset == "": self.ipset = None self.invert = invert if self.addr is None and self.ipset is None: raise FirewallError(errors.INVALID_RULE, "no address and ipset") def __str__(self): ret = 'destination%s ' % (" NOT" if self.invert else "") if self.addr is not None: return ret + 'address="%s"' % self.addr elif self.ipset is not None: return ret + 'ipset="%s"' % self.ipset else: raise FirewallError(errors.INVALID_RULE, "no address and ipset") class Rich_Service(object): def __init__(self, name): self.name = name def __str__(self): return 'service name="%s"' % (self.name) class Rich_Port(object): def __init__(self, port, protocol): self.port = port self.protocol = protocol def __str__(self): return 'port port="%s" protocol="%s"' % (self.port, self.protocol) class Rich_SourcePort(Rich_Port): def __str__(self): return 'source-port port="%s" protocol="%s"' % (self.port, self.protocol) class Rich_Protocol(object): def __init__(self, value): self.value = value def __str__(self): return 'protocol value="%s"' % (self.value) class Rich_Masquerade(object): def __init__(self): pass def __str__(self): return 'masquerade' class Rich_IcmpBlock(object): def __init__(self, name): self.name = name def __str__(self): return 'icmp-block name="%s"' % (self.name) class Rich_IcmpType(object): def __init__(self, name): self.name = name def __str__(self): return 'icmp-type name="%s"' % (self.name) class Rich_ForwardPort(object): def __init__(self, port, protocol, to_port, to_address): self.port = port self.protocol = protocol self.to_port = to_port self.to_address = to_address # replace None with "" in to_port and/or to_address if self.to_port is None: self.to_port = "" if self.to_address is None: self.to_address = "" def __str__(self): return 'forward-port port="%s" protocol="%s"%s%s' % \ (self.port, self.protocol, ' to-port="%s"' % self.to_port if self.to_port != "" else '', ' to-addr="%s"' % self.to_address if self.to_address != "" else '') class Rich_Log(object): def __init__(self, prefix=None, level=None, limit=None): #TODO check default level in iptables self.prefix = prefix self.level = level self.limit = limit def __str__(self): return 'log%s%s%s' % \ (' prefix="%s"' % (self.prefix) if self.prefix else "", ' level="%s"' % (self.level) if self.level else "", " %s" % self.limit if self.limit else "") class Rich_Audit(object): def __init__(self, limit=None): #TODO check default level in iptables self.limit = limit def __str__(self): return 'audit%s' % (" %s" % self.limit if self.limit else "") class Rich_Accept(object): def __init__(self, limit=None): self.limit = limit def __str__(self): return "accept%s" % (" %s" % self.limit if self.limit else "") class Rich_Reject(object): def __init__(self, _type=None, limit=None): self.type = _type self.limit = limit def __str__(self): return "reject%s%s" % (' type="%s"' % self.type if self.type else "", " %s" % self.limit if self.limit else "") def check(self, family): if self.type: if not family: raise FirewallError(errors.INVALID_RULE, "When using reject type you must specify also rule family.") if family in ['ipv4', 'ipv6'] and \ self.type not in REJECT_TYPES[family]: valid_types = ", ".join(REJECT_TYPES[family]) raise FirewallError(errors.INVALID_RULE, "Wrong reject type %s.\nUse one of: %s." % (self.type, valid_types)) class Rich_Drop(Rich_Accept): def __str__(self): return "drop%s" % (" %s" % self.limit if self.limit else "") class Rich_Mark(object): def __init__(self, _set, limit=None): self.set = _set self.limit = limit def __str__(self): return "mark set=%s%s" % (self.set, " %s" % self.limit if self.limit else "") def check(self): if self.set is not None: x = self.set else: raise FirewallError(errors.INVALID_MARK, "no value set") if "/" in x: splits = x.split("/") if len(splits) != 2: raise FirewallError(errors.INVALID_MARK, x) if not functions.checkUINT32(splits[0]) or \ not functions.checkUINT32(splits[1]): # value and mask are uint32 raise FirewallError(errors.INVALID_MARK, x) else: if not functions.checkUINT32(x): # value is uint32 raise FirewallError(errors.INVALID_MARK, x) DURATION_TO_MULT = { "s": 1, "m": 60, "h": 60 * 60, "d": 24 * 60 * 60, } class Rich_Limit(object): def __init__(self, value, burst=None): self.value = value self.burst = burst def check(self): self.value_parse() self.burst_parse() @property def value(self): return self._value @value.setter def value(self, value): if value is None: self._value = None return try: rate, duration = self._value_parse(value) except FirewallError: # The value is invalid. We cannot normalize it. v = value else: v = f"{rate}/{duration}" if getattr(self, "_value", None) != v: self._value = v @property def burst(self): return self._burst @burst.setter def burst(self, burst): if burst is None: self._burst = None return try: b = self._burst_parse(burst) except FirewallError: b = burst else: b = str(burst) if getattr(self, "_burst", None) != b: self._burst = b @staticmethod def _value_parse(value): splits = None if "/" in value: splits = value.split("/") if not splits or len(splits) != 2: raise FirewallError(errors.INVALID_LIMIT, value) (rate, duration) = splits try: rate = int(rate) except: raise FirewallError(errors.INVALID_LIMIT, value) if duration in ["second", "minute", "hour", "day"]: duration = duration[:1] if rate < 1 or duration not in ["s", "m", "h", "d"]: raise FirewallError(errors.INVALID_LIMIT, value) if 10000 * DURATION_TO_MULT[duration] // rate == 0: raise FirewallError(errors.INVALID_LIMIT, "%s too fast" % (value,)) if rate == 1 and duration == "d": # iptables (v1.4.21) doesn't accept 1/d raise FirewallError(errors.INVALID_LIMIT, "%s too slow" % (value,)) return rate, duration def value_parse(self): return self._value_parse(self._value) @staticmethod def _burst_parse(burst): if burst is None: return None try: b = int(burst) except: raise FirewallError(errors.INVALID_LIMIT, burst) if b < 1 or b > 10_000_000: raise FirewallError(errors.INVALID_LIMIT, burst) return b def burst_parse(self): return self._burst_parse(self._burst) def __str__(self): s = f'limit value="{self._value}"' if self._burst is not None: s += f" burst={self._burst}" return s class Rich_Rule(object): priority_min = -32768 priority_max = 32767 def __init__(self, family=None, rule_str=None, priority=0): if family is not None: self.family = str(family) else: self.family = None self.priority = priority self.source = None self.destination = None self.element = None self.log = None self.audit = None self.action = None if rule_str: self._import_from_string(rule_str) def _lexer(self, rule_str): """ Lexical analysis """ tokens = [] for r in functions.splitArgs(rule_str): if "=" in r: attr = r.split('=') if len(attr) != 2 or not attr[0] or not attr[1]: raise FirewallError(errors.INVALID_RULE, 'internal error in _lexer(): %s' % r) tokens.append({'attr_name':attr[0], 'attr_value':attr[1]}) else: tokens.append({'element':r}) tokens.append({'element':'EOL'}) return tokens def _import_from_string(self, rule_str): if not rule_str: raise FirewallError(errors.INVALID_RULE, 'empty rule') rule_str = functions.stripNonPrintableCharacters(rule_str) self.priority = 0 self.family = None self.source = None self.destination = None self.element = None self.log = None self.audit = None self.action = None tokens = self._lexer(rule_str) if tokens and tokens[0].get('element') == 'EOL': raise FirewallError(errors.INVALID_RULE, 'empty rule') attrs = {} # attributes of elements in_elements = [] # stack with elements we are in index = 0 # index into tokens while not (tokens[index].get('element') == 'EOL' and in_elements == ['rule']): element = tokens[index].get('element') attr_name = tokens[index].get('attr_name') attr_value = tokens[index].get('attr_value') #print ("in_elements: ", in_elements) #print ("index: %s, element: %s, attribute: %s=%s" % (index, element, attr_name, attr_value)) if attr_name: # attribute if attr_name not in ['priority', 'family', 'address', 'mac', 'ipset', 'invert', 'value', 'port', 'protocol', 'to-port', 'to-addr', 'name', 'prefix', 'level', 'type', 'set', 'burst']: raise FirewallError(errors.INVALID_RULE, "bad attribute '%s'" % attr_name) else: # element if element in ['rule', 'source', 'destination', 'protocol', 'service', 'port', 'icmp-block', 'icmp-type', 'masquerade', 'forward-port', 'source-port', 'log', 'audit', 'accept', 'drop', 'reject', 'mark', 'limit', 'not', 'NOT', 'EOL']: if element == 'source' and self.source: raise FirewallError(errors.INVALID_RULE, "more than one 'source' element") elif element == 'destination' and self.destination: raise FirewallError(errors.INVALID_RULE, "more than one 'destination' element") elif element in ['protocol', 'service', 'port', 'icmp-block', 'icmp-type', 'masquerade', 'forward-port', 'source-port'] and self.element: raise FirewallError(errors.INVALID_RULE, "more than one element. There cannot be both '%s' and '%s' in one rule." % (element, self.element)) elif element == 'log' and self.log: raise FirewallError(errors.INVALID_RULE, "more than one 'log' element") elif element == 'audit' and self.audit: raise FirewallError(errors.INVALID_RULE, "more than one 'audit' element") elif element in ['accept', 'drop', 'reject', 'mark'] and self.action: raise FirewallError(errors.INVALID_RULE, "more than one 'action' element. There cannot be both '%s' and '%s' in one rule." % (element, self.action)) else: raise FirewallError(errors.INVALID_RULE, "unknown element %s" % element) in_element = in_elements[len(in_elements)-1] if len(in_elements) > 0 else '' if in_element == '': if not element and attr_name: if attr_name == 'family': raise FirewallError(errors.INVALID_RULE, "'family' outside of rule. Use 'rule family=...'.") elif attr_name == 'priority': raise FirewallError(errors.INVALID_RULE, "'priority' outside of rule. Use 'rule priority=...'.") else: raise FirewallError(errors.INVALID_RULE, "'%s' outside of any element. Use 'rule %s= ...'." % (attr_name, attr_name)) elif 'rule' not in element: raise FirewallError(errors.INVALID_RULE, "'%s' outside of rule. Use 'rule ... %s ...'." % (element, element)) else: in_elements.append('rule') # push into stack elif in_element == 'rule': if attr_name == 'family': if attr_value not in ['ipv4', 'ipv6']: raise FirewallError(errors.INVALID_RULE, "'family' attribute cannot have '%s' value. Use 'ipv4' or 'ipv6' instead." % attr_value) self.family = attr_value elif attr_name == 'priority': try: self.priority = int(attr_value) except ValueError: raise FirewallError(errors.INVALID_PRIORITY, "invalid 'priority' attribute value '%s'." % attr_value) elif attr_name: if attr_name == 'protocol': err_msg = "wrong 'protocol' usage. Use either 'rule protocol value=...' or 'rule [forward-]port protocol=...'." else: err_msg = "attribute '%s' outside of any element. Use 'rule %s= ...'." % (attr_name, attr_name) raise FirewallError(errors.INVALID_RULE, err_msg) else: in_elements.append(element) # push into stack elif in_element == 'source': if attr_name in ['address', 'mac', 'ipset', 'invert']: attrs[attr_name] = attr_value elif element in ['not', 'NOT']: attrs['invert'] = True else: self.source = Rich_Source(attrs.get('address'), attrs.get('mac'), attrs.get('ipset'), attrs.get('invert', False)) in_elements.pop() # source attrs.clear() index = index -1 # return token to input elif in_element == 'destination': if attr_name in ['address', 'ipset', 'invert']: attrs[attr_name] = attr_value elif element in ['not', 'NOT']: attrs['invert'] = True else: self.destination = Rich_Destination(attrs.get('address'), attrs.get('ipset'), attrs.get('invert', False)) in_elements.pop() # destination attrs.clear() index = index -1 # return token to input elif in_element == 'protocol': if attr_name == 'value': self.element = Rich_Protocol(attr_value) in_elements.pop() # protocol else: raise FirewallError(errors.INVALID_RULE, "invalid 'protocol' element") elif in_element == 'service': if attr_name == 'name': self.element = Rich_Service(attr_value) in_elements.pop() # service else: raise FirewallError(errors.INVALID_RULE, "invalid 'service' element") elif in_element == 'port': if attr_name in ['port', 'protocol']: attrs[attr_name] = attr_value else: self.element = Rich_Port(attrs.get('port'), attrs.get('protocol')) in_elements.pop() # port attrs.clear() index = index -1 # return token to input elif in_element == 'icmp-block': if attr_name == 'name': self.element = Rich_IcmpBlock(attr_value) in_elements.pop() # icmp-block else: raise FirewallError(errors.INVALID_RULE, "invalid 'icmp-block' element") elif in_element == 'icmp-type': if attr_name == 'name': self.element = Rich_IcmpType(attr_value) in_elements.pop() # icmp-type else: raise FirewallError(errors.INVALID_RULE, "invalid 'icmp-type' element") elif in_element == 'masquerade': self.element = Rich_Masquerade() in_elements.pop() attrs.clear() index = index -1 # return token to input elif in_element == 'forward-port': if attr_name in ['port', 'protocol', 'to-port', 'to-addr']: attrs[attr_name] = attr_value else: self.element = Rich_ForwardPort(attrs.get('port'), attrs.get('protocol'), attrs.get('to-port'), attrs.get('to-addr')) in_elements.pop() # forward-port attrs.clear() index = index -1 # return token to input elif in_element == 'source-port': if attr_name in ['port', 'protocol']: attrs[attr_name] = attr_value else: self.element = Rich_SourcePort(attrs.get('port'), attrs.get('protocol')) in_elements.pop() # source-port attrs.clear() index = index -1 # return token to input elif in_element == 'log': if attr_name in ['prefix', 'level']: attrs[attr_name] = attr_value elif element == 'limit': in_elements.append('limit') else: self.log = Rich_Log(attrs.get('prefix'), attrs.get('level'), attrs.get('limit')) in_elements.pop() # log attrs.clear() index = index -1 # return token to input elif in_element == 'audit': if element == 'limit': in_elements.append('limit') else: self.audit = Rich_Audit(attrs.get('limit')) in_elements.pop() # audit attrs.clear() index = index -1 # return token to input elif in_element == 'accept': if element == 'limit': in_elements.append('limit') else: self.action = Rich_Accept(attrs.get('limit')) in_elements.pop() # accept attrs.clear() index = index -1 # return token to input elif in_element == 'drop': if element == 'limit': in_elements.append('limit') else: self.action = Rich_Drop(attrs.get('limit')) in_elements.pop() # drop attrs.clear() index = index -1 # return token to input elif in_element == 'reject': if attr_name == 'type': attrs[attr_name] = attr_value elif element == 'limit': in_elements.append('limit') else: self.action = Rich_Reject(attrs.get('type'), attrs.get('limit')) in_elements.pop() # accept attrs.clear() index = index -1 # return token to input elif in_element == 'mark': if attr_name == 'set': attrs[attr_name] = attr_value elif element == 'limit': in_elements.append('limit') else: self.action = Rich_Mark(attrs.get('set'), attrs.get('limit')) in_elements.pop() # accept attrs.clear() index = index -1 # return token to input elif in_element == 'limit': if attr_name in ["value", "burst"]: attrs[f"limit.{attr_name}"] = attr_value else: if "limit.value" not in attrs: raise FirewallError( errors.INVALID_RULE, "invalid 'limit' element" ) attrs["limit"] = Rich_Limit( attrs["limit.value"], attrs.get("limit.burst") ) attrs.pop("limit.value", None) attrs.pop("limit.burst", None) in_elements.pop() # limit index = index - 1 # return token to input index = index + 1 self.check() def check(self): if self.family is not None and self.family not in [ "ipv4", "ipv6" ]: raise FirewallError(errors.INVALID_FAMILY, self.family) if self.family is None: if (self.source is not None and self.source.addr is not None) or \ self.destination is not None: raise FirewallError(errors.MISSING_FAMILY) if type(self.element) == Rich_ForwardPort: raise FirewallError(errors.MISSING_FAMILY) if self.priority < self.priority_min or self.priority > self.priority_max: raise FirewallError(errors.INVALID_PRIORITY, "'priority' attribute must be between %d and %d." \ % (self.priority_min, self.priority_max)) if self.element is None and \ (self.log is None or (self.log is not None and self.priority == 0)): if self.action is None: raise FirewallError(errors.INVALID_RULE, "no element, no action") if self.source is None and self.destination is None and self.priority == 0: raise FirewallError(errors.INVALID_RULE, "no element, no source, no destination") if type(self.element) not in [ Rich_IcmpBlock, Rich_ForwardPort, Rich_Masquerade ]: if self.log is None and self.audit is None and \ self.action is None: raise FirewallError(errors.INVALID_RULE, "no action, no log, no audit") # source if self.source is not None: if self.source.addr is not None: if self.family is None: raise FirewallError(errors.INVALID_FAMILY) if self.source.mac is not None: raise FirewallError(errors.INVALID_RULE, "address and mac") if self.source.ipset is not None: raise FirewallError(errors.INVALID_RULE, "address and ipset") if not functions.check_address(self.family, self.source.addr): raise FirewallError(errors.INVALID_ADDR, str(self.source.addr)) elif self.source.mac is not None: if self.source.ipset is not None: raise FirewallError(errors.INVALID_RULE, "mac and ipset") if not functions.check_mac(self.source.mac): raise FirewallError(errors.INVALID_MAC, str(self.source.mac)) elif self.source.ipset is not None: if not check_ipset_name(self.source.ipset): raise FirewallError(errors.INVALID_IPSET, str(self.source.ipset)) else: raise FirewallError(errors.INVALID_RULE, "invalid source") # destination if self.destination is not None: if self.destination.addr is not None: if self.family is None: raise FirewallError(errors.INVALID_FAMILY) if self.destination.ipset is not None: raise FirewallError(errors.INVALID_DESTINATION, "address and ipset") if not functions.check_address(self.family, self.destination.addr): raise FirewallError(errors.INVALID_ADDR, str(self.destination.addr)) elif self.destination.ipset is not None: if not check_ipset_name(self.destination.ipset): raise FirewallError(errors.INVALID_IPSET, str(self.destination.ipset)) else: raise FirewallError(errors.INVALID_RULE, "invalid destination") # service if type(self.element) == Rich_Service: # service availability needs to be checked in Firewall, here is no # knowledge about this, therefore only simple check if self.element.name is None or len(self.element.name) < 1: raise FirewallError(errors.INVALID_SERVICE, str(self.element.name)) # port elif type(self.element) == Rich_Port: if not functions.check_port(self.element.port): raise FirewallError(errors.INVALID_PORT, self.element.port) if self.element.protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, self.element.protocol) # protocol elif type(self.element) == Rich_Protocol: if not functions.checkProtocol(self.element.value): raise FirewallError(errors.INVALID_PROTOCOL, self.element.value) # masquerade elif type(self.element) == Rich_Masquerade: if self.action is not None: raise FirewallError(errors.INVALID_RULE, "masquerade and action") if self.source is not None and self.source.mac is not None: raise FirewallError(errors.INVALID_RULE, "masquerade and mac source") # icmp-block elif type(self.element) == Rich_IcmpBlock: # icmp type availability needs to be checked in Firewall, here is no # knowledge about this, therefore only simple check if self.element.name is None or len(self.element.name) < 1: raise FirewallError(errors.INVALID_ICMPTYPE, str(self.element.name)) if self.action: raise FirewallError(errors.INVALID_RULE, "icmp-block and action") # icmp-type elif type(self.element) == Rich_IcmpType: # icmp type availability needs to be checked in Firewall, here is no # knowledge about this, therefore only simple check if self.element.name is None or len(self.element.name) < 1: raise FirewallError(errors.INVALID_ICMPTYPE, str(self.element.name)) # forward-port elif type(self.element) == Rich_ForwardPort: if not functions.check_port(self.element.port): raise FirewallError(errors.INVALID_PORT, self.element.port) if self.element.protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, self.element.protocol) if self.element.to_port == "" and self.element.to_address == "": raise FirewallError(errors.INVALID_PORT, self.element.to_port) if self.element.to_port != "" and \ not functions.check_port(self.element.to_port): raise FirewallError(errors.INVALID_PORT, self.element.to_port) if self.element.to_address != "" and \ not functions.check_single_address(self.family, self.element.to_address): raise FirewallError(errors.INVALID_ADDR, self.element.to_address) if self.family is None: raise FirewallError(errors.INVALID_FAMILY) if self.action is not None: raise FirewallError(errors.INVALID_RULE, "forward-port and action") # source-port elif type(self.element) == Rich_SourcePort: if not functions.check_port(self.element.port): raise FirewallError(errors.INVALID_PORT, self.element.port) if self.element.protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, self.element.protocol) # other element and not empty? elif self.element is not None: raise FirewallError(errors.INVALID_RULE, "Unknown element %s" % type(self.element)) # log if self.log is not None: if self.log.level and \ self.log.level not in [ "emerg", "alert", "crit", "error", "warning", "notice", "info", "debug" ]: raise FirewallError(errors.INVALID_LOG_LEVEL, self.log.level) if self.log.limit is not None: self.log.limit.check() # audit if self.audit is not None: if type(self.action) not in [ Rich_Accept, Rich_Reject, Rich_Drop ]: raise FirewallError(errors.INVALID_AUDIT_TYPE, type(self.action)) if self.audit.limit is not None: self.audit.limit.check() # action if self.action is not None: if type(self.action) == Rich_Reject: self.action.check(self.family) elif type(self.action) == Rich_Mark: self.action.check() if self.action.limit is not None: self.action.limit.check() def __str__(self): ret = 'rule' if self.priority: ret += ' priority="%d"' % self.priority if self.family: ret += ' family="%s"' % self.family if self.source: ret += " %s" % self.source if self.destination: ret += " %s" % self.destination if self.element: ret += " %s" % self.element if self.log: ret += " %s" % self.log if self.audit: ret += " %s" % self.audit if self.action: ret += " %s" % self.action return (functions.u2b(ret)) if functions.PY2 else ret #class Rich_RawRule(object): #class Rich_RuleSet(object): #class Rich_AddressList(object): PKpge[*fw_nm.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """Functions for NetworkManager interaction""" __all__ = [ "check_nm_imported", "nm_is_imported", "nm_get_zone_of_connection", "nm_set_zone_of_connection", "nm_get_connections", "nm_get_connection_of_interface", "nm_get_bus_name", "nm_get_dbus_interface" ] import gi from gi.repository import GLib try: gi.require_version('NM', '1.0') except ValueError: _nm_imported = False else: try: from gi.repository import NM _nm_imported = True except (ImportError, ValueError, GLib.Error): _nm_imported = False _nm_client = None from firewall import errors from firewall.errors import FirewallError from firewall.core.logger import log import dbus def check_nm_imported(): """Check function to raise a MISSING_IMPORT error if the import of NM failed """ if not _nm_imported: raise FirewallError(errors.MISSING_IMPORT, "gi.repository.NM = 1.0") def nm_is_imported(): """Returns true if NM has been properly imported @return True if import was successful, False otherwirse """ return _nm_imported def nm_get_client(): """Returns the NM client object or None if the import of NM failed @return NM.Client instance if import was successful, None otherwise """ global _nm_client if not _nm_client: _nm_client = NM.Client.new(None) return _nm_client def nm_get_zone_of_connection(connection): """Get zone of connection from NM @param connection name @return zone string setting of connection, empty string if not set, None if connection is unknown """ check_nm_imported() con = nm_get_client().get_connection_by_uuid(connection) if con is None: return None setting_con = con.get_setting_connection() if setting_con is None: return None try: if con.get_flags() & (NM.SettingsConnectionFlags.NM_GENERATED | NM.SettingsConnectionFlags.NM_VOLATILE): return "" except AttributeError: # Prior to NetworkManager 1.12, we can only guess # that a connection was generated/volatile. if con.get_unsaved(): return "" zone = setting_con.get_zone() if zone is None: zone = "" return zone def nm_set_zone_of_connection(zone, connection): """Set the zone for a connection @param zone name @param connection name @return True if zone was set, else False """ check_nm_imported() con = nm_get_client().get_connection_by_uuid(connection) if con is None: return False setting_con = con.get_setting_connection() if setting_con is None: return False if zone == "": zone = None setting_con.set_property("zone", zone) return con.commit_changes(True, None) def nm_get_connections(connections, connections_name): """Get active connections from NM @param connections return dict @param connections_name return dict """ connections.clear() connections_name.clear() check_nm_imported() active_connections = nm_get_client().get_active_connections() for active_con in active_connections: # ignore vpn devices for now if active_con.get_vpn(): continue name = active_con.get_id() uuid = active_con.get_uuid() devices = active_con.get_devices() connections_name[uuid] = name for dev in devices: ip_iface = dev.get_ip_iface() if ip_iface: connections[ip_iface] = uuid def nm_get_interfaces(): """Get active interfaces from NM @returns list of interface names """ check_nm_imported() active_interfaces = [] for active_con in nm_get_client().get_active_connections(): # ignore vpn devices for now if active_con.get_vpn(): continue try: con = active_con.get_connection() if con.get_flags() & (NM.SettingsConnectionFlags.NM_GENERATED | NM.SettingsConnectionFlags.NM_VOLATILE): continue except AttributeError: # Prior to NetworkManager 1.12, we can only guess # that a connection was generated/volatile. if con.get_unsaved(): continue for dev in active_con.get_devices(): ip_iface = dev.get_ip_iface() if ip_iface: active_interfaces.append(ip_iface) return active_interfaces def nm_get_interfaces_in_zone(zone): interfaces = [] for interface in nm_get_interfaces(): conn = nm_get_connection_of_interface(interface) if zone == nm_get_zone_of_connection(conn): interfaces.append(interface) return interfaces def nm_get_device_by_ip_iface(interface): """Get device from NM which has the given IP interface @param interface name @returns NM.Device instance or None """ check_nm_imported() for device in nm_get_client().get_devices(): ip_iface = device.get_ip_iface() if ip_iface is None: continue if ip_iface == interface: return device return None def nm_get_connection_of_interface(interface): """Get connection from NM that is using the interface @param interface name @returns connection that is using interface or None """ check_nm_imported() device = nm_get_device_by_ip_iface(interface) if device is None: return None active_con = device.get_active_connection() if active_con is None: return None try: con = active_con.get_connection() if con.get_flags() & NM.SettingsConnectionFlags.NM_GENERATED: return None except AttributeError: # Prior to NetworkManager 1.12, we can only guess # that a connection was generated. if con.get_unsaved(): return None return active_con.get_uuid() def nm_get_bus_name(): if not _nm_imported: return None try: bus = dbus.SystemBus() obj = bus.get_object(NM.DBUS_INTERFACE, NM.DBUS_PATH) name = obj.bus_name del obj, bus return name except Exception: log.debug2("Failed to get bus name of NetworkManager") return None def nm_get_dbus_interface(): if not _nm_imported: return "" return NM.DBUS_INTERFACE PKpge[\yy fw_zone.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import time import copy from firewall.core.base import SHORTCUTS, DEFAULT_ZONE_TARGET, SOURCE_IPSET_TYPES from firewall.core.fw_transaction import FirewallTransaction from firewall.core.io.policy import Policy from firewall.core.logger import log from firewall.core.rich import Rich_Service, Rich_Port, Rich_Protocol, Rich_SourcePort, Rich_ForwardPort, \ Rich_IcmpBlock, Rich_IcmpType, Rich_Masquerade, Rich_Mark from firewall.functions import checkIPnMask, checkIP6nMask, check_mac from firewall import errors from firewall.errors import FirewallError from firewall.fw_types import LastUpdatedOrderedDict class FirewallZone(object): ZONE_POLICY_PRIORITY = 0 def __init__(self, fw): self._fw = fw self._zones = { } self._zone_policies = { } def __repr__(self): return '%s(%r)' % (self.__class__, self._zones) def cleanup(self): self._zones.clear() self._zone_policies.clear() def new_transaction(self): return FirewallTransaction(self._fw) def policy_name_from_zones(self, fromZone, toZone): return "zone_{fromZone}_{toZone}".format(fromZone=fromZone, toZone=toZone) # zones def get_zones(self): return sorted(self._zones.keys()) def get_active_zones(self): active_zones = [] for zone in self.get_zones(): if self.list_interfaces(zone) or self.list_sources(zone): active_zones.append(zone) return active_zones def get_zone_of_interface(self, interface): interface_id = self.__interface_id(interface) for zone in self._zones: if interface_id in self._zones[zone].settings["interfaces"]: # an interface can only be part of one zone return zone return None def get_zone_of_source(self, source): source_id = self.__source_id(source) for zone in self._zones: if source_id in self._zones[zone].settings["sources"]: # a source_id can only be part of one zone return zone return None def get_zone(self, zone): z = self._fw.check_zone(zone) return self._zones[z] def policy_obj_from_zone_obj(self, z_obj, fromZone, toZone): p_obj = Policy() p_obj.derived_from_zone = z_obj.name p_obj.name = self.policy_name_from_zones(fromZone, toZone) p_obj.priority = self.ZONE_POLICY_PRIORITY p_obj.target = z_obj.target p_obj.ingress_zones = [fromZone] p_obj.egress_zones = [toZone] # copy zone permanent config to policy permanent config # WARN: This assumes the same attribute names. # for setting in ["services", "ports", "masquerade", "forward_ports", "source_ports", "icmp_blocks", "rules", "protocols"]: if fromZone == z_obj.name and toZone == "HOST" and \ setting in ["services", "ports", "source_ports", "icmp_blocks", "protocols"]: # zone --> HOST setattr(p_obj, setting, copy.deepcopy(getattr(z_obj, setting))) elif fromZone == "ANY" and toZone == z_obj.name and setting in ["masquerade"]: # any zone --> zone setattr(p_obj, setting, copy.deepcopy(getattr(z_obj, setting))) elif fromZone == z_obj.name and toZone == "ANY" and \ setting in ["icmp_blocks", "forward_ports"]: # zone --> any zone setattr(p_obj, setting, copy.deepcopy(getattr(z_obj, setting))) elif setting in ["rules"]: p_obj.rules = [] for rule in z_obj.rules: current_policy = self.policy_name_from_zones(fromZone, toZone) if current_policy in self._rich_rule_to_policies(z_obj.name, rule): p_obj.rules.append(copy.deepcopy(rule)) return p_obj def add_zone(self, obj): obj.settings = { x : LastUpdatedOrderedDict() for x in ["interfaces", "sources", "icmp_block_inversion", "forward"] } self._zones[obj.name] = obj self._zone_policies[obj.name] = [] # Create policy objects, will need many: # - (zone --> HOST) - ports, service, etc # - (any zone --> zone) - masquerade # - (zone --> any zone) - ICMP block, icmp block inversion # - also includes forward-ports because it works on (nat, # PREROUTING) and therefore applies to redirects to the local # host or dnat to a different host. # - also includes rich rule "mark" action for the same reason # for fromZone,toZone in [(obj.name, "HOST"), ("ANY", obj.name), (obj.name, "ANY")]: p_obj = self.policy_obj_from_zone_obj(obj, fromZone, toZone) self._fw.policy.add_policy(p_obj) self._zone_policies[obj.name].append(p_obj.name) self.copy_permanent_to_runtime(obj.name) def copy_permanent_to_runtime(self, zone): obj = self._zones[zone] for arg in obj.interfaces: self.add_interface(zone, arg, allow_apply=False) for arg in obj.sources: self.add_source(zone, arg, allow_apply=False) if obj.forward: self.add_forward(zone) if obj.icmp_block_inversion: self.add_icmp_block_inversion(zone) def remove_zone(self, zone): obj = self._zones[zone] if obj.applied: self.unapply_zone_settings(zone) obj.settings.clear() del self._zones[zone] del self._zone_policies[zone] def apply_zones(self, use_transaction=None): for zone in self.get_zones(): z_obj = self._zones[zone] if len(z_obj.interfaces) > 0 or len(z_obj.sources) > 0: log.debug1("Applying zone '%s'", zone) self.apply_zone_settings(zone, use_transaction=use_transaction) def set_zone_applied(self, zone, applied): obj = self._zones[zone] obj.applied = applied # zone from chain def zone_from_chain(self, chain): if "_" not in chain: # no zone chain return None splits = chain.split("_") if len(splits) < 2: return None _chain = None for x in SHORTCUTS: if splits[0] == SHORTCUTS[x]: _chain = x if _chain is not None: # next part needs to be zone name if splits[1] not in self.get_zones(): return None if len(splits) == 2 or \ (len(splits) == 3 and splits[2] in [ "pre", "log", "deny", "allow", "post" ]): return (splits[1], _chain) return None def policy_from_chain(self, chain): x = self.zone_from_chain(chain) if x is None: return None (zone, _chain) = x # derived from _get_table_chains_for_zone_dispatch() if _chain in ["PREROUTING", "FORWARD_IN"]: fromZone = zone toZone = "ANY" elif _chain in ["INPUT"]: fromZone = zone toZone = "HOST" elif _chain in ["POSTROUTING", "FORWARD_OUT"]: fromZone = "ANY" toZone = zone else: raise FirewallError(errors.INVALID_CHAIN, "chain '%s' can't be mapped to a policy" % (chain)) return (self.policy_name_from_zones(fromZone, toZone), _chain) def create_zone_base_by_chain(self, ipv, table, chain, use_transaction=None): # Create zone base chains if the chain is reserved for a zone if ipv in [ "ipv4", "ipv6" ]: x = self.policy_from_chain(chain) if x is not None: (policy, _chain) = self.policy_from_chain(chain) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self._fw.policy.gen_chain_rules(policy, True, table, _chain, transaction) if use_transaction is None: transaction.execute(True) # settings # generate settings record with sender, timeout def __gen_settings(self, timeout, sender): ret = { "date": time.time(), "sender": sender, "timeout": timeout, } return ret def get_settings(self, zone): return self.get_zone(zone).settings def _zone_settings(self, enable, zone, transaction): settings = self.get_settings(zone) for key in settings: for args in settings[key]: if key == "interfaces": self._interface(enable, zone, args, transaction) elif key == "sources": self._source(enable, zone, args[0], args[1], transaction) elif key == "icmp_block_inversion": continue elif key == "forward": # no need to call this when applying the zone as the rules # will be generated when adding the interfaces/sources pass else: log.warning("Zone '%s': Unknown setting '%s:%s', " "unable to apply", zone, key, args) # ICMP-block-inversion is always applied if enable: self._icmp_block_inversion(enable, zone, transaction) def apply_zone_settings(self, zone, use_transaction=None): _zone = self._fw.check_zone(zone) obj = self._zones[_zone] if obj.applied: return obj.applied = True if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction for policy in self._zone_policies[_zone]: log.debug1("Applying policy (%s) derived from zone '%s'", policy, zone) self._fw.policy.apply_policy_settings(policy, use_transaction=transaction) self._zone_settings(True, _zone, transaction) if use_transaction is None: transaction.execute(True) def unapply_zone_settings(self, zone, use_transaction=None): _zone = self._fw.check_zone(zone) obj = self._zones[_zone] if not obj.applied: return if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction for policy in self._zone_policies[_zone]: self._fw.policy.unapply_policy_settings(policy, use_transaction=transaction) self._zone_settings(False, _zone, transaction) if use_transaction is None: transaction.execute(True) def get_config_with_settings(self, zone): """ :return: exported config updated with runtime settings """ obj = self.get_zone(zone) conf_dict = self.get_config_with_settings_dict(zone) conf_list = [] for i in range(16): # tuple based API has 16 elements if obj.IMPORT_EXPORT_STRUCTURE[i][0] not in conf_dict: # old API needs the empty elements as well. Grab it from the # class otherwise we don't know the type. conf_list.append(copy.deepcopy(getattr(obj, obj.IMPORT_EXPORT_STRUCTURE[i][0]))) else: conf_list.append(conf_dict[obj.IMPORT_EXPORT_STRUCTURE[i][0]]) return tuple(conf_list) def get_config_with_settings_dict(self, zone): """ :return: exported config updated with runtime settings """ permanent = self.get_zone(zone).export_config_dict() if permanent["target"] == DEFAULT_ZONE_TARGET: permanent["target"] = "default" runtime = { "services": self.list_services(zone), "ports": self.list_ports(zone), "icmp_blocks": self.list_icmp_blocks(zone), "masquerade": self.query_masquerade(zone), "forward_ports": self.list_forward_ports(zone), "interfaces": self.list_interfaces(zone), "sources": self.list_sources(zone), "rules_str": self.list_rules(zone), "protocols": self.list_protocols(zone), "source_ports": self.list_source_ports(zone), "icmp_block_inversion": self.query_icmp_block_inversion(zone), "forward": self.query_forward(zone), } return self._fw.combine_runtime_with_permanent_settings(permanent, runtime) def set_config_with_settings_dict(self, zone, settings, sender): # stupid wrappers to convert rich rule string to rich rule object from firewall.core.rich import Rich_Rule def add_rule_wrapper(zone, rule_str, timeout=0, sender=None): self.add_rule(zone, Rich_Rule(rule_str=rule_str), timeout=0, sender=sender) def remove_rule_wrapper(zone, rule_str): self.remove_rule(zone, Rich_Rule(rule_str=rule_str)) setting_to_fn = { "services": (self.add_service, self.remove_service), "ports": (self.add_port, self.remove_port), "icmp_blocks": (self.add_icmp_block, self.remove_icmp_block), "masquerade": (self.add_masquerade, self.remove_masquerade), "forward_ports": (self.add_forward_port, self.remove_forward_port), "interfaces": (self.add_interface, self.remove_interface), "sources": (self.add_source, self.remove_source), "rules_str": (add_rule_wrapper, remove_rule_wrapper), "protocols": (self.add_protocol, self.remove_protocol), "source_ports": (self.add_source_port, self.remove_source_port), "icmp_block_inversion": (self.add_icmp_block_inversion, self.remove_icmp_block_inversion), "forward": (self.add_forward, self.remove_forward), } old_settings = self.get_config_with_settings_dict(zone) (add_settings, remove_settings) = self._fw.get_added_and_removed_settings(old_settings, settings) for key in remove_settings: if isinstance(remove_settings[key], list): for args in remove_settings[key]: if isinstance(args, tuple): setting_to_fn[key][1](zone, *args) else: setting_to_fn[key][1](zone, args) else: # bool setting_to_fn[key][1](zone) for key in add_settings: if isinstance(add_settings[key], list): for args in add_settings[key]: if key in ["interfaces", "sources"]: # no timeout arg setting_to_fn[key][0](zone, args, sender=sender) else: if isinstance(args, tuple): setting_to_fn[key][0](zone, *args, timeout=0, sender=sender) else: setting_to_fn[key][0](zone, args, timeout=0, sender=sender) else: # bool if key in ["icmp_block_inversion"]: # no timeout arg setting_to_fn[key][0](zone, sender=sender) else: setting_to_fn[key][0](zone, timeout=0, sender=sender) # INTERFACES def check_interface(self, interface): self._fw.check_interface(interface) def interface_get_sender(self, zone, interface): _zone = self._fw.check_zone(zone) _obj = self._zones[_zone] interface_id = self.__interface_id(interface) if interface_id in _obj.settings["interfaces"]: settings = _obj.settings["interfaces"][interface_id] if "sender" in settings and settings["sender"] is not None: return settings["sender"] return None def __interface_id(self, interface): self.check_interface(interface) return interface def add_interface(self, zone, interface, sender=None, use_transaction=None, allow_apply=True): self._fw.check_panic() _zone = self._fw.check_zone(zone) _obj = self._zones[_zone] interface_id = self.__interface_id(interface) if interface_id in _obj.settings["interfaces"]: raise FirewallError(errors.ZONE_ALREADY_SET, "'%s' already bound to '%s'" % (interface, zone)) if self.get_zone_of_interface(interface) is not None: raise FirewallError(errors.ZONE_CONFLICT, "'%s' already bound to a zone" % interface) log.debug1("Setting zone of interface '%s' to '%s'" % (interface, _zone)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if not _obj.applied and allow_apply: self.apply_zone_settings(zone, use_transaction=transaction) transaction.add_fail(self.set_zone_applied, _zone, False) if allow_apply: self._interface(True, _zone, interface, transaction) self.__register_interface(_obj, interface_id, zone, sender) transaction.add_fail(self.__unregister_interface, _obj, interface_id) if use_transaction is None: transaction.execute(True) return _zone def __register_interface(self, _obj, interface_id, zone, sender): _obj.settings["interfaces"][interface_id] = \ self.__gen_settings(0, sender) # add information whether we add to default or specific zone _obj.settings["interfaces"][interface_id]["__default__"] = \ (not zone or zone == "") def change_zone_of_interface(self, zone, interface, sender=None): self._fw.check_panic() _old_zone = self.get_zone_of_interface(interface) _new_zone = self._fw.check_zone(zone) if _new_zone == _old_zone: return _old_zone if _old_zone is not None: self.remove_interface(_old_zone, interface) _zone = self.add_interface(zone, interface, sender) return _zone def change_default_zone(self, old_zone, new_zone, use_transaction=None): self._fw.check_panic() if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self.apply_zone_settings(new_zone, transaction) self._interface(True, new_zone, "+", transaction, append=True) if old_zone is not None and old_zone != "": self._interface(False, old_zone, "+", transaction, append=True) if use_transaction is None: transaction.execute(True) def remove_interface(self, zone, interface, use_transaction=None): self._fw.check_panic() zoi = self.get_zone_of_interface(interface) if zoi is None: raise FirewallError(errors.UNKNOWN_INTERFACE, "'%s' is not in any zone" % interface) _zone = zoi if zone == "" else self._fw.check_zone(zone) if zoi != _zone: raise FirewallError(errors.ZONE_CONFLICT, "remove_interface(%s, %s): zoi='%s'" % \ (zone, interface, zoi)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction _obj = self._zones[_zone] interface_id = self.__interface_id(interface) transaction.add_post(self.__unregister_interface, _obj, interface_id) self._interface(False, _zone, interface, transaction) if use_transaction is None: transaction.execute(True) return _zone def __unregister_interface(self, _obj, interface_id): if interface_id in _obj.settings["interfaces"]: del _obj.settings["interfaces"][interface_id] def query_interface(self, zone, interface): return self.__interface_id(interface) in self.get_settings(zone)["interfaces"] def list_interfaces(self, zone): return self.get_settings(zone)["interfaces"].keys() # SOURCES def check_source(self, source, applied=False): if checkIPnMask(source): return "ipv4" elif checkIP6nMask(source): return "ipv6" elif check_mac(source): return "" elif source.startswith("ipset:"): self._check_ipset_type_for_source(source[6:]) if applied: self._check_ipset_applied(source[6:]) return self._ipset_family(source[6:]) else: raise FirewallError(errors.INVALID_ADDR, source) def __source_id(self, source, applied=False): ipv = self.check_source(source, applied=applied) return (ipv, source) def add_source(self, zone, source, sender=None, use_transaction=None, allow_apply=True): self._fw.check_panic() _zone = self._fw.check_zone(zone) _obj = self._zones[_zone] if check_mac(source): source = source.upper() source_id = self.__source_id(source, applied=allow_apply) if source_id in _obj.settings["sources"]: raise FirewallError(errors.ZONE_ALREADY_SET, "'%s' already bound to '%s'" % (source, _zone)) if self.get_zone_of_source(source) is not None: raise FirewallError(errors.ZONE_CONFLICT, "'%s' already bound to a zone" % source) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if not _obj.applied and allow_apply: self.apply_zone_settings(zone, use_transaction=transaction) transaction.add_fail(self.set_zone_applied, _zone, False) if allow_apply: self._source(True, _zone, source_id[0], source_id[1], transaction) self.__register_source(_obj, source_id, zone, sender) transaction.add_fail(self.__unregister_source, _obj, source_id) if use_transaction is None: transaction.execute(True) return _zone def __register_source(self, _obj, source_id, zone, sender): _obj.settings["sources"][source_id] = \ self.__gen_settings(0, sender) # add information whether we add to default or specific zone _obj.settings["sources"][source_id]["__default__"] = (not zone or zone == "") def change_zone_of_source(self, zone, source, sender=None): self._fw.check_panic() _old_zone = self.get_zone_of_source(source) _new_zone = self._fw.check_zone(zone) if _new_zone == _old_zone: return _old_zone if check_mac(source): source = source.upper() if _old_zone is not None: self.remove_source(_old_zone, source) _zone = self.add_source(zone, source, sender) return _zone def remove_source(self, zone, source, use_transaction=None): self._fw.check_panic() if check_mac(source): source = source.upper() zos = self.get_zone_of_source(source) if zos is None: raise FirewallError(errors.UNKNOWN_SOURCE, "'%s' is not in any zone" % source) _zone = zos if zone == "" else self._fw.check_zone(zone) if zos != _zone: raise FirewallError(errors.ZONE_CONFLICT, "remove_source(%s, %s): zos='%s'" % \ (zone, source, zos)) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction _obj = self._zones[_zone] source_id = self.__source_id(source) transaction.add_post(self.__unregister_source, _obj, source_id) self._source(False, _zone, source_id[0], source_id[1], transaction) if use_transaction is None: transaction.execute(True) return _zone def __unregister_source(self, _obj, source_id): if source_id in _obj.settings["sources"]: del _obj.settings["sources"][source_id] def query_source(self, zone, source): if check_mac(source): source = source.upper() return self.__source_id(source) in self.get_settings(zone)["sources"] def list_sources(self, zone): return [ k[1] for k in self.get_settings(zone)["sources"].keys() ] def _interface(self, enable, zone, interface, transaction, append=False): for backend in self._fw.enabled_backends(): if not backend.policies_supported: continue for policy in self._zone_policies[zone]: for (table, chain) in self._fw.policy._get_table_chains_for_zone_dispatch(policy): rules = backend.build_zone_source_interface_rules(enable, zone, policy, interface, table, chain, append) transaction.add_rules(backend, rules) # intra zone forward policy = self.policy_name_from_zones(zone, "ANY") # Skip adding wildcard/catch-all interface (for default # zone). Otherwise it would allow forwarding from interface # in default zone -> interface not in default zone (but in # a different zone). if self.get_settings(zone)["forward"] and interface not in ["+", "*"]: rules = backend.build_zone_forward_rules(enable, zone, policy, "filter", interface=interface) transaction.add_rules(backend, rules) # update policy dispatch for any policy using this zone in ingress # or egress for policy in self._fw.policy.get_policies_not_derived_from_zone(): if zone not in self._fw.policy.list_ingress_zones(policy) and \ zone not in self._fw.policy.list_egress_zones(policy): continue if policy in self._fw.policy.get_active_policies_not_derived_from_zone() and self._fw.policy.get_policy(policy).applied: # first remove the old set of interfaces using the current zone # settings. if not enable and len(self.list_interfaces(zone)) == 1: self._fw.policy.unapply_policy_settings(policy, use_transaction=transaction) else: self._fw.policy._ingress_egress_zones(False, policy, transaction) # after the transaction ends and therefore the interface # has been added to the zone's settings, update the # dependent policies transaction.add_post(lambda p: (p in self._fw.policy.get_active_policies_not_derived_from_zone()) and \ self._fw.policy._ingress_egress_zones_transaction(True, p), policy) elif enable: transaction.add_post(lambda p: (p in self._fw.policy.get_active_policies_not_derived_from_zone()) and \ self._fw.policy.apply_policy_settings(p), policy) # IPSETS def _ipset_family(self, name): if self._ipset_type(name) == "hash:mac": return None return self._fw.ipset.get_family(name, applied=False) def _ipset_type(self, name): return self._fw.ipset.get_type(name, applied=False) def _ipset_match_flags(self, name, flag): return ",".join([flag] * self._fw.ipset.get_dimension(name)) def _check_ipset_applied(self, name): return self._fw.ipset.check_applied(name) def _check_ipset_type_for_source(self, name): _type = self._ipset_type(name) if _type not in SOURCE_IPSET_TYPES: raise FirewallError( errors.INVALID_IPSET, "ipset '%s' with type '%s' not usable as source" % \ (name, _type)) def _source(self, enable, zone, ipv, source, transaction): # For mac source bindings ipv is an empty string, the mac source will # be added for ipv4 and ipv6 for backend in [self._fw.get_backend_by_ipv(ipv)] if ipv else self._fw.enabled_backends(): if not backend.policies_supported: continue for policy in self._zone_policies[zone]: for (table, chain) in self._fw.policy._get_table_chains_for_zone_dispatch(policy): rules = backend.build_zone_source_address_rules(enable, zone, policy, source, table, chain) transaction.add_rules(backend, rules) # intra zone forward policy = self.policy_name_from_zones(zone, "ANY") if self.get_settings(zone)["forward"]: rules = backend.build_zone_forward_rules(enable, zone, policy, "filter", source=source) transaction.add_rules(backend, rules) # update policy dispatch for any policy using this zone in ingress # or egress for policy in self._fw.policy.get_policies_not_derived_from_zone(): if zone not in self._fw.policy.list_ingress_zones(policy) and \ zone not in self._fw.policy.list_egress_zones(policy): continue if policy in self._fw.policy.get_active_policies_not_derived_from_zone() and self._fw.policy.get_policy(policy).applied: # first remove the old set of sources using the current zone # settings. if not enable and len(self.list_sources(zone)) == 1: self._fw.policy.unapply_policy_settings(policy, use_transaction=transaction) else: self._fw.policy._ingress_egress_zones(False, policy, transaction) # after the transaction ends and therefore the sources # has been added to the zone's settings, update the # dependent policies transaction.add_post(lambda p: (p in self._fw.policy.get_active_policies_not_derived_from_zone()) and \ self._fw.policy._ingress_egress_zones_transaction(True, p), policy) elif enable: transaction.add_post(lambda p: (p in self._fw.policy.get_active_policies_not_derived_from_zone()) and \ self._fw.policy.apply_policy_settings(p), policy) def add_service(self, zone, service, timeout=0, sender=None): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.add_service(p_name, service, timeout, sender) return zone def remove_service(self, zone, service): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.remove_service(p_name, service) return zone def query_service(self, zone, service): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") return self._fw.policy.query_service(p_name, service) def list_services(self, zone): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") return self._fw.policy.list_services(p_name) def add_port(self, zone, port, protocol, timeout=0, sender=None): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.add_port(p_name, port, protocol, timeout, sender) return zone def remove_port(self, zone, port, protocol): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.remove_port(p_name, port, protocol) return zone def query_port(self, zone, port, protocol): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") return self._fw.policy.query_port(p_name, port, protocol) def list_ports(self, zone): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") return self._fw.policy.list_ports(p_name) def add_source_port(self, zone, source_port, protocol, timeout=0, sender=None): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.add_source_port(p_name, source_port, protocol, timeout, sender) return zone def remove_source_port(self, zone, source_port, protocol): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.remove_source_port(p_name, source_port, protocol) return zone def query_source_port(self, zone, source_port, protocol): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") return self._fw.policy.query_source_port(p_name, source_port, protocol) def list_source_ports(self, zone): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") return self._fw.policy.list_source_ports(p_name) def _rich_rule_to_policies(self, zone, rule): zone = self._fw.check_zone(zone) if type(rule.action) == Rich_Mark: return [self.policy_name_from_zones(zone, "ANY")] elif type(rule.element) in [Rich_Service, Rich_Port, Rich_Protocol, Rich_SourcePort]: return [self.policy_name_from_zones(zone, "HOST")] elif type(rule.element) in [Rich_IcmpBlock, Rich_IcmpType]: return [self.policy_name_from_zones(zone, "HOST"), self.policy_name_from_zones(zone, "ANY")] elif type(rule.element) in [Rich_ForwardPort]: return [self.policy_name_from_zones(zone, "ANY")] elif type(rule.element) in [Rich_Masquerade]: return [self.policy_name_from_zones("ANY", zone)] elif rule.element is None: return [self.policy_name_from_zones(zone, "HOST")] else: raise FirewallError("Rich rule type (%s) not handled." % (type(rule.element))) def add_rule(self, zone, rule, timeout=0, sender=None): for p_name in self._rich_rule_to_policies(zone, rule): self._fw.policy.add_rule(p_name, rule, timeout, sender) return zone def remove_rule(self, zone, rule): for p_name in self._rich_rule_to_policies(zone, rule): self._fw.policy.remove_rule(p_name, rule) return zone def query_rule(self, zone, rule): ret = True for p_name in self._rich_rule_to_policies(zone, rule): ret = ret and self._fw.policy.query_rule(p_name, rule) return ret def list_rules(self, zone): zone = self._fw.check_zone(zone) ret = set() for p_name in [self.policy_name_from_zones(zone, "ANY"), self.policy_name_from_zones(zone, "HOST"), self.policy_name_from_zones("ANY", zone)]: ret.update(set(self._fw.policy.list_rules(p_name))) return list(ret) def add_protocol(self, zone, protocol, timeout=0, sender=None): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.add_protocol(p_name, protocol, timeout, sender) return zone def remove_protocol(self, zone, protocol): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.remove_protocol(p_name, protocol) return zone def query_protocol(self, zone, protocol): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") return self._fw.policy.query_protocol(p_name, protocol) def list_protocols(self, zone): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") return self._fw.policy.list_protocols(p_name) def add_masquerade(self, zone, timeout=0, sender=None): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones("ANY", zone) self._fw.policy.add_masquerade(p_name, timeout, sender) return zone def remove_masquerade(self, zone): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones("ANY", zone) self._fw.policy.remove_masquerade(p_name) return zone def query_masquerade(self, zone): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones("ANY", zone) return self._fw.policy.query_masquerade(p_name) def add_forward_port(self, zone, port, protocol, toport=None, toaddr=None, timeout=0, sender=None): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "ANY") self._fw.policy.add_forward_port(p_name, port, protocol, toport, toaddr, timeout, sender) return zone def remove_forward_port(self, zone, port, protocol, toport=None, toaddr=None): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "ANY") self._fw.policy.remove_forward_port(p_name, port, protocol, toport, toaddr) return zone def query_forward_port(self, zone, port, protocol, toport=None, toaddr=None): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "ANY") return self._fw.policy.query_forward_port(p_name, port, protocol, toport, toaddr) def list_forward_ports(self, zone): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "ANY") return self._fw.policy.list_forward_ports(p_name) def add_icmp_block(self, zone, icmp, timeout=0, sender=None): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.add_icmp_block(p_name, icmp, timeout, sender) p_name = self.policy_name_from_zones(zone, "ANY") self._fw.policy.add_icmp_block(p_name, icmp, timeout, sender) return zone def remove_icmp_block(self, zone, icmp): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.remove_icmp_block(p_name, icmp) p_name = self.policy_name_from_zones(zone, "ANY") self._fw.policy.remove_icmp_block(p_name, icmp) return zone def query_icmp_block(self, zone, icmp): zone = self._fw.check_zone(zone) p_name_host = self.policy_name_from_zones(zone, "HOST") p_name_fwd = self.policy_name_from_zones(zone, "ANY") return self._fw.policy.query_icmp_block(p_name_host, icmp) and \ self._fw.policy.query_icmp_block(p_name_fwd, icmp) def list_icmp_blocks(self, zone): zone = self._fw.check_zone(zone) p_name_host = self.policy_name_from_zones(zone, "HOST") p_name_fwd = self.policy_name_from_zones(zone, "ANY") return sorted(set(self._fw.policy.list_icmp_blocks(p_name_host) + self._fw.policy.list_icmp_blocks(p_name_fwd))) def add_icmp_block_inversion(self, zone, sender=None): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.add_icmp_block_inversion(p_name, sender) p_name = self.policy_name_from_zones(zone, "ANY") self._fw.policy.add_icmp_block_inversion(p_name, sender) return zone def _icmp_block_inversion(self, enable, zone, transaction): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy._icmp_block_inversion(enable, p_name, transaction) p_name = self.policy_name_from_zones(zone, "ANY") self._fw.policy._icmp_block_inversion(enable, p_name, transaction) def remove_icmp_block_inversion(self, zone): zone = self._fw.check_zone(zone) p_name = self.policy_name_from_zones(zone, "HOST") self._fw.policy.remove_icmp_block_inversion(p_name) p_name = self.policy_name_from_zones(zone, "ANY") self._fw.policy.remove_icmp_block_inversion(p_name) return zone def query_icmp_block_inversion(self, zone): zone = self._fw.check_zone(zone) p_name_host = self.policy_name_from_zones(zone, "HOST") p_name_fwd = self.policy_name_from_zones(zone, "ANY") return self._fw.policy.query_icmp_block_inversion(p_name_host) and \ self._fw.policy.query_icmp_block_inversion(p_name_fwd) def _forward(self, enable, zone, transaction): p_name = self.policy_name_from_zones(zone, "ANY") for interface in self._zones[zone].settings["interfaces"]: for backend in self._fw.enabled_backends(): if not backend.policies_supported: continue rules = backend.build_zone_forward_rules(enable, zone, p_name, "filter", interface=interface) transaction.add_rules(backend, rules) for ipv,source in self._zones[zone].settings["sources"]: for backend in [self._fw.get_backend_by_ipv(ipv)] if ipv else self._fw.enabled_backends(): if not backend.policies_supported: continue rules = backend.build_zone_forward_rules(enable, zone, p_name, "filter", source=source) transaction.add_rules(backend, rules) def __forward_id(self): return True def add_forward(self, zone, timeout=0, sender=None, use_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_timeout(timeout) self._fw.check_panic() _obj = self._zones[_zone] forward_id = self.__forward_id() if forward_id in _obj.settings["forward"]: raise FirewallError(errors.ALREADY_ENABLED, "forward already enabled in '%s'" % _zone) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._forward(True, _zone, transaction) self.__register_forward(_obj, forward_id, timeout, sender) transaction.add_fail(self.__unregister_forward, _obj, forward_id) if use_transaction is None: transaction.execute(True) return _zone def __register_forward(self, _obj, forward_id, timeout, sender): _obj.settings["forward"][forward_id] = \ self.__gen_settings(timeout, sender) def remove_forward(self, zone, use_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] forward_id = self.__forward_id() if forward_id not in _obj.settings["forward"]: raise FirewallError(errors.NOT_ENABLED, "forward not enabled in '%s'" % _zone) if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if _obj.applied: self._forward(False, _zone, transaction) transaction.add_post(self.__unregister_forward, _obj, forward_id) if use_transaction is None: transaction.execute(True) return _zone def __unregister_forward(self, _obj, forward_id): if forward_id in _obj.settings["forward"]: del _obj.settings["forward"][forward_id] def query_forward(self, zone): return self.__forward_id() in self.get_settings(zone)["forward"] PKpge[266base.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """Base firewall settings""" DEFAULT_ZONE_TARGET = "{chain}_{zone}" DEFAULT_POLICY_TARGET = "CONTINUE" DEFAULT_POLICY_PRIORITY = -1 ZONE_TARGETS = [ "ACCEPT", "%%REJECT%%", "DROP", DEFAULT_ZONE_TARGET, "default" ] POLICY_TARGETS = [ "ACCEPT", "REJECT", "DROP", "CONTINUE" ] SHORTCUTS = { "PREROUTING": "PRE", "POSTROUTING": "POST", "INPUT": "IN", "FORWARD_IN": "FWDI", "FORWARD_OUT": "FWDO", "OUTPUT": "OUT", } REJECT_TYPES = { "ipv4": [ "icmp-host-prohibited", "host-prohib", "icmp-net-unreachable", "net-unreach", "icmp-host-unreachable", "host-unreach", "icmp-port-unreachable", "port-unreach", "icmp-proto-unreachable", "proto-unreach", "icmp-net-prohibited", "net-prohib", "tcp-reset", "tcp-rst", "icmp-admin-prohibited", "admin-prohib" ], "ipv6": [ "icmp6-adm-prohibited", "adm-prohibited", "icmp6-no-route", "no-route", "icmp6-addr-unreachable", "addr-unreach", "icmp6-port-unreachable", "port-unreach", "tcp-reset" ] } # ipset types that can be used as a source in zones # The match-set option will be src or src,src according to the # dimension of the ipset. SOURCE_IPSET_TYPES = [ "hash:ip", "hash:ip,port", "hash:ip,mark", "hash:net", "hash:net,port", "hash:net,iface", "hash:mac" ] PKpge[ɶ ipXtables.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import os.path import copy from firewall.core.prog import runProg from firewall.core.logger import log from firewall.functions import tempFile, readfile, splitArgs, check_mac, portStr, \ check_single_address, check_address, normalizeIP6 from firewall import config from firewall.errors import FirewallError, INVALID_PASSTHROUGH, INVALID_RULE, UNKNOWN_ERROR, INVALID_ADDR from firewall.core.rich import Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark, \ Rich_Masquerade, Rich_ForwardPort, Rich_IcmpBlock import string POLICY_CHAIN_PREFIX = "" BUILT_IN_CHAINS = { "security": [ "INPUT", "OUTPUT", "FORWARD" ], "raw": [ "PREROUTING", "OUTPUT" ], "mangle": [ "PREROUTING", "POSTROUTING", "INPUT", "OUTPUT", "FORWARD" ], "nat": [ "PREROUTING", "POSTROUTING", "OUTPUT" ], "filter": [ "INPUT", "OUTPUT", "FORWARD" ], } DEFAULT_REJECT_TYPE = { "ipv4": "icmp-host-prohibited", "ipv6": "icmp6-adm-prohibited", } ICMP = { "ipv4": "icmp", "ipv6": "ipv6-icmp", } # ipv ebtables also uses this # def common_reverse_rule(args): """ Inverse valid rule """ replace_args = { # Append "-A": "-D", "--append": "--delete", # Insert "-I": "-D", "--insert": "--delete", # New chain "-N": "-X", "--new-chain": "--delete-chain", } ret_args = args[:] for arg in replace_args: try: idx = ret_args.index(arg) except Exception: continue if arg in [ "-I", "--insert" ]: # With insert rulenum, then remove it if it is a number # Opt at position idx, chain at position idx+1, [rulenum] at # position idx+2 try: int(ret_args[idx+2]) except Exception: pass else: ret_args.pop(idx+2) ret_args[idx] = replace_args[arg] return ret_args def common_reverse_passthrough(args): """ Reverse valid passthough rule """ replace_args = { # Append "-A": "-D", "--append": "--delete", # Insert "-I": "-D", "--insert": "--delete", # New chain "-N": "-X", "--new-chain": "--delete-chain", } ret_args = args[:] for x in replace_args: try: idx = ret_args.index(x) except ValueError: continue if x in [ "-I", "--insert" ]: # With insert rulenum, then remove it if it is a number # Opt at position idx, chain at position idx+1, [rulenum] at # position idx+2 try: int(ret_args[idx+2]) except ValueError: pass else: ret_args.pop(idx+2) ret_args[idx] = replace_args[x] return ret_args raise FirewallError(INVALID_PASSTHROUGH, "no '-A', '-I' or '-N' arg") # ipv ebtables also uses this # def common_check_passthrough(args): """ Check if passthough rule is valid (only add, insert and new chain rules are allowed) """ args = set(args) not_allowed = set(["-C", "--check", # check rule "-D", "--delete", # delete rule "-R", "--replace", # replace rule "-L", "--list", # list rule "-S", "--list-rules", # print rules "-F", "--flush", # flush rules "-Z", "--zero", # zero rules "-X", "--delete-chain", # delete chain "-P", "--policy", # policy "-E", "--rename-chain"]) # rename chain) # intersection of args and not_allowed is not empty, i.e. # something from args is not allowed if len(args & not_allowed) > 0: raise FirewallError(INVALID_PASSTHROUGH, "arg '%s' is not allowed" % list(args & not_allowed)[0]) # args need to contain one of -A, -I, -N needed = set(["-A", "--append", "-I", "--insert", "-N", "--new-chain"]) # empty intersection of args and needed, i.e. # none from args contains any needed command if len(args & needed) == 0: raise FirewallError(INVALID_PASSTHROUGH, "no '-A', '-I' or '-N' arg") class ip4tables(object): ipv = "ipv4" name = "ip4tables" policies_supported = True def __init__(self, fw): self._fw = fw self._command = config.COMMANDS[self.ipv] self._restore_command = config.COMMANDS["%s-restore" % self.ipv] self.wait_option = self._detect_wait_option() self.restore_wait_option = self._detect_restore_wait_option() self.fill_exists() self.available_tables = [] self.rich_rule_priority_counts = {} self.policy_priority_counts = {} self.zone_source_index_cache = [] self.our_chains = {} # chains created by firewalld def fill_exists(self): self.command_exists = os.path.exists(self._command) self.restore_command_exists = os.path.exists(self._restore_command) def __run(self, args): # convert to string list if self.wait_option and self.wait_option not in args: _args = [self.wait_option] + ["%s" % item for item in args] else: _args = ["%s" % item for item in args] log.debug2("%s: %s %s", self.__class__, self._command, " ".join(_args)) (status, ret) = runProg(self._command, _args) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._command, " ".join(_args), ret)) return ret def _rule_replace(self, rule, pattern, replacement): try: i = rule.index(pattern) except ValueError: return False else: rule[i:i+1] = replacement return True def is_chain_builtin(self, ipv, table, chain): return table in BUILT_IN_CHAINS and \ chain in BUILT_IN_CHAINS[table] def build_chain_rules(self, add, table, chain): rule = [ "-t", table ] if add: rule.append("-N") else: rule.append("-X") rule.append(chain) return [rule] def build_rule(self, add, table, chain, index, args): rule = [ "-t", table ] if add: rule += [ "-I", chain, str(index) ] else: rule += [ "-D", chain ] rule += args return rule def reverse_rule(self, args): return common_reverse_rule(args) def check_passthrough(self, args): common_check_passthrough(args) def reverse_passthrough(self, args): return common_reverse_passthrough(args) def passthrough_parse_table_chain(self, args): table = "filter" try: i = args.index("-t") except ValueError: pass else: if len(args) >= i+1: table = args[i+1] chain = None for opt in [ "-A", "--append", "-I", "--insert", "-N", "--new-chain" ]: try: i = args.index(opt) except ValueError: pass else: if len(args) >= i+1: chain = args[i+1] return (table, chain) def _run_replace_zone_source(self, rule, zone_source_index_cache): try: i = rule.index("%%ZONE_SOURCE%%") rule.pop(i) zone = rule.pop(i) if "-m" == rule[4]: # ipset/mac zone_source = (zone, rule[7]) # (zone, address) else: zone_source = (zone, rule[5]) # (zone, address) except ValueError: try: i = rule.index("%%ZONE_INTERFACE%%") rule.pop(i) zone_source = None except ValueError: return rule_add = True if rule[0] in ["-D", "--delete"]: rule_add = False if zone_source and not rule_add: if zone_source in zone_source_index_cache: zone_source_index_cache.remove(zone_source) elif rule_add: if zone_source: # order source based dispatch by zone name if zone_source not in zone_source_index_cache: zone_source_index_cache.append(zone_source) zone_source_index_cache.sort(key=lambda x: x[0]) index = zone_source_index_cache.index(zone_source) else: if self._fw._allow_zone_drifting: index = 0 else: index = len(zone_source_index_cache) rule[0] = "-I" rule.insert(2, "%d" % (index + 1)) def _set_rule_replace_priority(self, rule, priority_counts, token): """ Change something like -t filter -I public_IN %%RICH_RULE_PRIORITY%% 123 or -t filter -A public_IN %%RICH_RULE_PRIORITY%% 321 into -t filter -I public_IN 4 or -t filter -I public_IN """ try: i = rule.index(token) except ValueError: pass else: rule_add = True insert = False insert_add_index = -1 rule.pop(i) priority = rule.pop(i) if type(priority) != int: raise FirewallError(INVALID_RULE, "priority must be followed by a number") table = "filter" for opt in [ "-t", "--table" ]: try: j = rule.index(opt) except ValueError: pass else: if len(rule) >= j+1: table = rule[j+1] for opt in [ "-A", "--append", "-I", "--insert", "-D", "--delete" ]: try: insert_add_index = rule.index(opt) except ValueError: pass else: if len(rule) >= insert_add_index+1: chain = rule[insert_add_index+1] if opt in [ "-I", "--insert" ]: insert = True if opt in [ "-D", "--delete" ]: rule_add = False chain = (table, chain) # Add the rule to the priority counts. We don't need to store the # rule, just bump the ref count for the priority value. if not rule_add: if chain not in priority_counts or \ priority not in priority_counts[chain] or \ priority_counts[chain][priority] <= 0: raise FirewallError(UNKNOWN_ERROR, "nonexistent or underflow of priority count") priority_counts[chain][priority] -= 1 else: if chain not in priority_counts: priority_counts[chain] = {} if priority not in priority_counts[chain]: priority_counts[chain][priority] = 0 # calculate index of new rule index = 1 for p in sorted(priority_counts[chain].keys()): if p == priority and insert: break index += priority_counts[chain][p] if p == priority: break priority_counts[chain][priority] += 1 rule[insert_add_index] = "-I" rule.insert(insert_add_index+2, "%d" % index) def set_rules(self, rules, log_denied): temp_file = tempFile() table_rules = { } rich_rule_priority_counts = copy.deepcopy(self.rich_rule_priority_counts) policy_priority_counts = copy.deepcopy(self.policy_priority_counts) zone_source_index_cache = copy.deepcopy(self.zone_source_index_cache) for _rule in rules: rule = _rule[:] # replace %%REJECT%% self._rule_replace(rule, "%%REJECT%%", \ ["REJECT", "--reject-with", DEFAULT_REJECT_TYPE[self.ipv]]) # replace %%ICMP%% self._rule_replace(rule, "%%ICMP%%", [ICMP[self.ipv]]) # replace %%LOGTYPE%% try: i = rule.index("%%LOGTYPE%%") except ValueError: pass else: if log_denied == "off": continue if log_denied in [ "unicast", "broadcast", "multicast" ]: rule[i:i+1] = [ "-m", "pkttype", "--pkt-type", log_denied ] else: rule.pop(i) self._set_rule_replace_priority(rule, rich_rule_priority_counts, "%%RICH_RULE_PRIORITY%%") self._set_rule_replace_priority(rule, policy_priority_counts, "%%POLICY_PRIORITY%%") self._run_replace_zone_source(rule, zone_source_index_cache) table = "filter" # get table form rule for opt in [ "-t", "--table" ]: try: i = rule.index(opt) except ValueError: pass else: if len(rule) >= i+1: rule.pop(i) table = rule.pop(i) # we can not use joinArgs here, because it would use "'" instead # of '"' for the start and end of the string, this breaks # iptables-restore for i in range(len(rule)): for c in string.whitespace: if c in rule[i] and not (rule[i].startswith('"') and rule[i].endswith('"')): rule[i] = '"%s"' % rule[i] table_rules.setdefault(table, []).append(rule) for table in table_rules: rules = table_rules[table] temp_file.write("*%s\n" % table) for rule in rules: temp_file.write(" ".join(rule) + "\n") temp_file.write("COMMIT\n") temp_file.close() stat = os.stat(temp_file.name) log.debug2("%s: %s %s", self.__class__, self._restore_command, "%s: %d" % (temp_file.name, stat.st_size)) args = [ ] if self.restore_wait_option: args.append(self.restore_wait_option) args.append("-n") (status, ret) = runProg(self._restore_command, args, stdin=temp_file.name) if log.getDebugLogLevel() > 2: lines = readfile(temp_file.name) if lines is not None: i = 1 for line in lines: log.debug3("%8d: %s" % (i, line), nofmt=1, nl=0) if not line.endswith("\n"): log.debug3("", nofmt=1) i += 1 os.unlink(temp_file.name) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._restore_command, " ".join(args), ret)) self.rich_rule_priority_counts = rich_rule_priority_counts self.policy_priority_counts = policy_priority_counts self.zone_source_index_cache = zone_source_index_cache def set_rule(self, rule, log_denied): # replace %%REJECT%% self._rule_replace(rule, "%%REJECT%%", \ ["REJECT", "--reject-with", DEFAULT_REJECT_TYPE[self.ipv]]) # replace %%ICMP%% self._rule_replace(rule, "%%ICMP%%", [ICMP[self.ipv]]) # replace %%LOGTYPE%% try: i = rule.index("%%LOGTYPE%%") except ValueError: pass else: if log_denied == "off": return "" if log_denied in [ "unicast", "broadcast", "multicast" ]: rule[i:i+1] = [ "-m", "pkttype", "--pkt-type", log_denied ] else: rule.pop(i) rich_rule_priority_counts = copy.deepcopy(self.rich_rule_priority_counts) policy_priority_counts = copy.deepcopy(self.policy_priority_counts) zone_source_index_cache = copy.deepcopy(self.zone_source_index_cache) self._set_rule_replace_priority(rule, rich_rule_priority_counts, "%%RICH_RULE_PRIORITY%%") self._set_rule_replace_priority(rule, policy_priority_counts, "%%POLICY_PRIORITY%%") self._run_replace_zone_source(rule, zone_source_index_cache) output = self.__run(rule) self.rich_rule_priority_counts = rich_rule_priority_counts self.policy_priority_counts = policy_priority_counts self.zone_source_index_cache = zone_source_index_cache return output def get_available_tables(self, table=None): ret = [] tables = [ table ] if table else BUILT_IN_CHAINS.keys() for table in tables: if table in self.available_tables: ret.append(table) else: try: self.__run(["-t", table, "-L", "-n"]) self.available_tables.append(table) ret.append(table) except ValueError: log.debug1("%s table '%s' does not exist (or not enough permission to check)." % (self.ipv, table)) return ret def _detect_wait_option(self): wait_option = "" ret = runProg(self._command, ["-w", "-L", "-n"]) # since iptables-1.4.20 if ret[0] == 0: wait_option = "-w" # wait for xtables lock ret = runProg(self._command, ["-w10", "-L", "-n"]) # since iptables > 1.4.21 if ret[0] == 0: wait_option = "-w10" # wait max 10 seconds log.debug2("%s: %s will be using %s option.", self.__class__, self._command, wait_option) return wait_option def _detect_restore_wait_option(self): temp_file = tempFile() temp_file.write("#foo") temp_file.close() wait_option = "" for test_option in ["-w", "--wait=2"]: ret = runProg(self._restore_command, [test_option], stdin=temp_file.name) if ret[0] == 0 and "invalid option" not in ret[1] \ and "unrecognized option" not in ret[1]: wait_option = test_option break log.debug2("%s: %s will be using %s option.", self.__class__, self._restore_command, wait_option) os.unlink(temp_file.name) return wait_option def build_flush_rules(self): self.rich_rule_priority_counts = {} self.policy_priority_counts = {} self.zone_source_index_cache = [] rules = [] for table in BUILT_IN_CHAINS.keys(): if not self.get_available_tables(table): continue # Flush firewall rules: -F # Delete firewall chains: -X # Set counter to zero: -Z for flag in [ "-F", "-X", "-Z" ]: rules.append(["-t", table, flag]) return rules def build_set_policy_rules(self, policy): rules = [] _policy = "DROP" if policy == "PANIC" else policy for table in BUILT_IN_CHAINS.keys(): if not self.get_available_tables(table): continue if table == "nat": continue for chain in BUILT_IN_CHAINS[table]: rules.append(["-t", table, "-P", chain, _policy]) return rules def supported_icmp_types(self, ipv=None): """Return ICMP types that are supported by the iptables/ip6tables command and kernel""" ret = [ ] output = "" try: output = self.__run(["-p", "icmp" if self.ipv == "ipv4" else "ipv6-icmp", "--help"]) except ValueError as ex: if self.ipv == "ipv4": log.debug1("iptables error: %s" % ex) else: log.debug1("ip6tables error: %s" % ex) lines = output.splitlines() in_types = False for line in lines: #print(line) if in_types: line = line.strip().lower() splits = line.split() for split in splits: if split.startswith("(") and split.endswith(")"): x = split[1:-1] else: x = split if x not in ret: ret.append(x) if self.ipv == "ipv4" and line.startswith("Valid ICMP Types:") or \ self.ipv == "ipv6" and line.startswith("Valid ICMPv6 Types:"): in_types = True return ret def build_default_tables(self): # nothing to do, they always exist return [] def build_default_rules(self, log_denied="off"): default_rules = {} if self.get_available_tables("security"): default_rules["security"] = [ ] self.our_chains["security"] = set() for chain in BUILT_IN_CHAINS["security"]: default_rules["security"].append("-N %s_direct" % chain) default_rules["security"].append("-A %s -j %s_direct" % (chain, chain)) self.our_chains["security"].add("%s_direct" % chain) if self.get_available_tables("raw"): default_rules["raw"] = [ ] self.our_chains["raw"] = set() for chain in BUILT_IN_CHAINS["raw"]: default_rules["raw"].append("-N %s_direct" % chain) default_rules["raw"].append("-A %s -j %s_direct" % (chain, chain)) self.our_chains["raw"].add("%s_direct" % chain) if chain == "PREROUTING": for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]: default_rules["raw"].append("-N %s_%s" % (chain, dispatch_suffix)) default_rules["raw"].append("-A %s -j %s_%s" % (chain, chain, dispatch_suffix)) self.our_chains["raw"].update(set(["%s_%s" % (chain, dispatch_suffix)])) if self.get_available_tables("mangle"): default_rules["mangle"] = [ ] self.our_chains["mangle"] = set() for chain in BUILT_IN_CHAINS["mangle"]: default_rules["mangle"].append("-N %s_direct" % chain) default_rules["mangle"].append("-A %s -j %s_direct" % (chain, chain)) self.our_chains["mangle"].add("%s_direct" % chain) if chain == "PREROUTING": for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]: default_rules["mangle"].append("-N %s_%s" % (chain, dispatch_suffix)) default_rules["mangle"].append("-A %s -j %s_%s" % (chain, chain, dispatch_suffix)) self.our_chains["mangle"].update(set(["%s_%s" % (chain, dispatch_suffix)])) if self.get_available_tables("nat"): default_rules["nat"] = [ ] self.our_chains["nat"] = set() for chain in BUILT_IN_CHAINS["nat"]: default_rules["nat"].append("-N %s_direct" % chain) default_rules["nat"].append("-A %s -j %s_direct" % (chain, chain)) self.our_chains["nat"].add("%s_direct" % chain) if chain in [ "PREROUTING", "POSTROUTING" ]: for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]: default_rules["nat"].append("-N %s_%s" % (chain, dispatch_suffix)) default_rules["nat"].append("-A %s -j %s_%s" % (chain, chain, dispatch_suffix)) self.our_chains["nat"].update(set(["%s_%s" % (chain, dispatch_suffix)])) default_rules["filter"] = [] self.our_chains["filter"] = set() default_rules["filter"].append("-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPT") default_rules["filter"].append("-A INPUT -i lo -j ACCEPT") default_rules["filter"].append("-N INPUT_direct") default_rules["filter"].append("-A INPUT -j INPUT_direct") self.our_chains["filter"].update(set("INPUT_direct")) for dispatch_suffix in ["POLICIES_pre", "ZONES_SOURCE", "ZONES", "POLICIES_post"] if self._fw._allow_zone_drifting else ["POLICIES_pre", "ZONES", "POLICIES_post"]: default_rules["filter"].append("-N INPUT_%s" % (dispatch_suffix)) default_rules["filter"].append("-A INPUT -j INPUT_%s" % (dispatch_suffix)) self.our_chains["filter"].update(set("INPUT_%s" % (dispatch_suffix))) if log_denied != "off": default_rules["filter"].append("-A INPUT -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: '") default_rules["filter"].append("-A INPUT -m conntrack --ctstate INVALID -j DROP") if log_denied != "off": default_rules["filter"].append("-A INPUT %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: '") default_rules["filter"].append("-A INPUT -j %%REJECT%%") default_rules["filter"].append("-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPT") default_rules["filter"].append("-A FORWARD -i lo -j ACCEPT") default_rules["filter"].append("-N FORWARD_direct") default_rules["filter"].append("-A FORWARD -j FORWARD_direct") self.our_chains["filter"].update(set("FORWARD_direct")) for dispatch_suffix in ["POLICIES_pre"]: default_rules["filter"].append("-N FORWARD_%s" % (dispatch_suffix)) default_rules["filter"].append("-A FORWARD -j FORWARD_%s" % (dispatch_suffix)) self.our_chains["filter"].update(set("FORWARD_%s" % (dispatch_suffix))) for direction in ["IN", "OUT"]: for dispatch_suffix in ["ZONES_SOURCE", "ZONES"] if self._fw._allow_zone_drifting else ["ZONES"]: default_rules["filter"].append("-N FORWARD_%s_%s" % (direction, dispatch_suffix)) default_rules["filter"].append("-A FORWARD -j FORWARD_%s_%s" % (direction, dispatch_suffix)) self.our_chains["filter"].update(set("FORWARD_%s_%s" % (direction, dispatch_suffix))) for dispatch_suffix in ["POLICIES_post"]: default_rules["filter"].append("-N FORWARD_%s" % (dispatch_suffix)) default_rules["filter"].append("-A FORWARD -j FORWARD_%s" % (dispatch_suffix)) self.our_chains["filter"].update(set("FORWARD_%s" % (dispatch_suffix))) if log_denied != "off": default_rules["filter"].append("-A FORWARD -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: '") default_rules["filter"].append("-A FORWARD -m conntrack --ctstate INVALID -j DROP") if log_denied != "off": default_rules["filter"].append("-A FORWARD %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: '") default_rules["filter"].append("-A FORWARD -j %%REJECT%%") default_rules["filter"] += [ "-N OUTPUT_direct", "-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT", "-A OUTPUT -o lo -j ACCEPT", "-A OUTPUT -j OUTPUT_direct", ] self.our_chains["filter"].update(set("OUTPUT_direct")) for dispatch_suffix in ["POLICIES_pre"]: default_rules["filter"].append("-N OUTPUT_%s" % (dispatch_suffix)) default_rules["filter"].append("-A OUTPUT -j OUTPUT_%s" % (dispatch_suffix)) self.our_chains["filter"].update(set("OUTPUT_%s" % (dispatch_suffix))) for dispatch_suffix in ["POLICIES_post"]: default_rules["filter"].append("-N OUTPUT_%s" % (dispatch_suffix)) default_rules["filter"].append("-A OUTPUT -j OUTPUT_%s" % (dispatch_suffix)) self.our_chains["filter"].update(set("OUTPUT_%s" % (dispatch_suffix))) final_default_rules = [] for table in default_rules: if table not in self.get_available_tables(): continue for rule in default_rules[table]: final_default_rules.append(["-t", table] + splitArgs(rule)) return final_default_rules def get_zone_table_chains(self, table): if table == "filter": return { "INPUT", "FORWARD_IN", "FORWARD_OUT" } if table == "mangle": if "mangle" in self.get_available_tables(): return { "PREROUTING" } if table == "nat": if "nat" in self.get_available_tables(): return { "PREROUTING", "POSTROUTING" } if table == "raw": if "raw" in self.get_available_tables(): return { "PREROUTING" } return {} def build_policy_ingress_egress_rules(self, enable, policy, table, chain, ingress_interfaces, egress_interfaces, ingress_sources, egress_sources): p_obj = self._fw.policy.get_policy(policy) chain_suffix = "pre" if p_obj.priority < 0 else "post" isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT) ingress_fragments = [] egress_fragments = [] for interface in ingress_interfaces: ingress_fragments.append(["-i", interface]) for interface in egress_interfaces: egress_fragments.append(["-o", interface]) for addr in ingress_sources: ipv = self._fw.zone.check_source(addr) if ipv in ["ipv4", "ipv6"] and not self.is_ipv_supported(ipv): continue ingress_fragments.append(self._rule_addr_fragment("-s", addr)) for addr in egress_sources: ipv = self._fw.zone.check_source(addr) if ipv in ["ipv4", "ipv6"] and not self.is_ipv_supported(ipv): continue # iptables can not match destination MAC if check_mac(addr) and chain in ["POSTROUTING", "FORWARD_OUT", "OUTPUT"]: continue egress_fragments.append(self._rule_addr_fragment("-d", addr)) def _generate_policy_dispatch_rule(ingress_fragment, egress_fragment): add_del = {True: "-A", False: "-D" }[enable] rule = ["-t", table, add_del, "%s_POLICIES_%s" % (chain, chain_suffix), "%%POLICY_PRIORITY%%", p_obj.priority] if ingress_fragment: rule.extend(ingress_fragment) if egress_fragment: rule.extend(egress_fragment) rule.extend(["-j", _policy]) return rule rules = [] if ingress_fragments: # zone --> [zone, ANY, HOST] for ingress_fragment in ingress_fragments: # zone --> zone if egress_fragments: for egress_fragment in egress_fragments: rules.append(_generate_policy_dispatch_rule(ingress_fragment, egress_fragment)) elif egress_sources: # if the egress source is not for the current family (there # are no egress fragments), then avoid creating an invalid # catch all rule. pass else: rules.append(_generate_policy_dispatch_rule(ingress_fragment, None)) elif ingress_sources: # if the ingress source is not for the current family (there are no # ingress fragments), then avoid creating an invalid catch all # rule. pass else: # [ANY, HOST] --> [zone, ANY, HOST] # [ANY, HOST] --> zone if egress_fragments: for egress_fragment in egress_fragments: rules.append(_generate_policy_dispatch_rule(None, egress_fragment)) elif egress_sources: # if the egress source is not for the current family (there # are no egress fragments), then avoid creating an invalid # catch all rule. pass else: # [ANY, HOST] --> [ANY, HOST] rules.append(_generate_policy_dispatch_rule(None, None)) return rules def build_zone_source_interface_rules(self, enable, zone, policy, interface, table, chain, append=False): isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT) opt = { "PREROUTING": "-i", "POSTROUTING": "-o", "INPUT": "-i", "FORWARD_IN": "-i", "FORWARD_OUT": "-o", "OUTPUT": "-o", }[chain] action = "-g" if enable and not append: rule = [ "-I", "%s_ZONES" % chain, "%%ZONE_INTERFACE%%" ] elif enable: rule = [ "-A", "%s_ZONES" % chain ] else: rule = [ "-D", "%s_ZONES" % chain ] if not append: rule += ["%%ZONE_INTERFACE%%"] rule += [ "-t", table, opt, interface, action, _policy ] return [rule] def _rule_addr_fragment(self, opt, address, invert=False): if address.startswith("ipset:"): name = address[6:] if opt == "-d": opt = "dst" else: opt = "src" flags = ",".join([opt] * self._fw.ipset.get_dimension(name)) return ["-m", "set", "--match-set", name, flags] elif check_mac(address): # outgoing can not be set if opt == "-d": raise FirewallError(INVALID_ADDR, "Can't match a destination MAC.") return ["-m", "mac", "--mac-source", address.upper()] else: if check_single_address("ipv6", address): address = normalizeIP6(address) elif check_address("ipv6", address): addr_split = address.split("/") address = normalizeIP6(addr_split[0]) + "/" + addr_split[1] return [opt, address] def build_zone_source_address_rules(self, enable, zone, policy, address, table, chain): add_del = { True: "-I", False: "-D" }[enable] isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT) opt = { "PREROUTING": "-s", "POSTROUTING": "-d", "INPUT": "-s", "FORWARD_IN": "-s", "FORWARD_OUT": "-d", "OUTPUT": "-d", }[chain] if self._fw._allow_zone_drifting: zone_dispatch_chain = "%s_ZONES_SOURCE" % (chain) else: zone_dispatch_chain = "%s_ZONES" % (chain) # iptables can not match destination MAC if check_mac(address) and chain in ["POSTROUTING", "FORWARD_OUT", "OUTPUT"]: return [] rule = [add_del, zone_dispatch_chain, "%%ZONE_SOURCE%%", zone, "-t", table] rule.extend(self._rule_addr_fragment(opt, address)) rule.extend(["-g", _policy]) return [rule] def build_policy_chain_rules(self, enable, policy, table, chain): add_del_chain = { True: "-N", False: "-X" }[enable] add_del_rule = { True: "-A", False: "-D" }[enable] isSNAT = True if (table == "nat" and chain == "POSTROUTING") else False _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=isSNAT) self.our_chains[table].update(set([_policy, "%s_log" % _policy, "%s_deny" % _policy, "%s_pre" % _policy, "%s_post" % _policy, "%s_allow" % _policy])) rules = [] rules.append([ add_del_chain, _policy, "-t", table ]) rules.append([ add_del_chain, "%s_pre" % _policy, "-t", table ]) rules.append([ add_del_chain, "%s_log" % _policy, "-t", table ]) rules.append([ add_del_chain, "%s_deny" % _policy, "-t", table ]) rules.append([ add_del_chain, "%s_allow" % _policy, "-t", table ]) rules.append([ add_del_chain, "%s_post" % _policy, "-t", table ]) rules.append([ add_del_rule, _policy, "-t", table, "-j", "%s_pre" % _policy ]) rules.append([ add_del_rule, _policy, "-t", table, "-j", "%s_log" % _policy ]) rules.append([ add_del_rule, _policy, "-t", table, "-j", "%s_deny" % _policy ]) rules.append([ add_del_rule, _policy, "-t", table, "-j", "%s_allow" % _policy ]) rules.append([ add_del_rule, _policy, "-t", table, "-j", "%s_post" % _policy ]) target = self._fw.policy._policies[policy].target if self._fw.get_log_denied() != "off": if table == "filter": if target in [ "REJECT", "%%REJECT%%" ]: rules.append([ add_del_rule, _policy, "-t", table, "%%LOGTYPE%%", "-j", "LOG", "--log-prefix", "\"%s_REJECT: \"" % _policy ]) if target == "DROP": rules.append([ add_del_rule, _policy, "-t", table, "%%LOGTYPE%%", "-j", "LOG", "--log-prefix", "\"%s_DROP: \"" % _policy ]) if table == "filter" and \ target in [ "ACCEPT", "REJECT", "%%REJECT%%", "DROP" ]: rules.append([ add_del_rule, _policy, "-t", table, "-j", target ]) if not enable: rules.reverse() return rules def _rule_limit(self, limit): if not limit: return [] s = ["-m", "limit", "--limit", limit.value] if limit.burst is not None: s += ["--limit-burst", limit.burst] return s def _rich_rule_chain_suffix(self, rich_rule): if type(rich_rule.element) in [Rich_Masquerade, Rich_ForwardPort, Rich_IcmpBlock]: # These are special and don't have an explicit action pass elif rich_rule.action: if type(rich_rule.action) not in [Rich_Accept, Rich_Reject, Rich_Drop, Rich_Mark]: raise FirewallError(INVALID_RULE, "Unknown action %s" % type(rich_rule.action)) else: raise FirewallError(INVALID_RULE, "No rule action specified.") if rich_rule.priority == 0: if type(rich_rule.element) in [Rich_Masquerade, Rich_ForwardPort] or \ type(rich_rule.action) in [Rich_Accept, Rich_Mark]: return "allow" elif type(rich_rule.element) in [Rich_IcmpBlock] or \ type(rich_rule.action) in [Rich_Reject, Rich_Drop]: return "deny" elif rich_rule.priority < 0: return "pre" else: return "post" def _rich_rule_chain_suffix_from_log(self, rich_rule): if not rich_rule.log and not rich_rule.audit: raise FirewallError(INVALID_RULE, "Not log or audit") if rich_rule.priority == 0: return "log" elif rich_rule.priority < 0: return "pre" else: return "post" def _rich_rule_priority_fragment(self, rich_rule): if rich_rule.priority == 0: return [] return ["%%RICH_RULE_PRIORITY%%", rich_rule.priority] def _rich_rule_log(self, policy, rich_rule, enable, table, rule_fragment): if not rich_rule.log: return [] _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "-A", False: "-D" }[enable] chain_suffix = self._rich_rule_chain_suffix_from_log(rich_rule) rule = ["-t", table, add_del, "%s_%s" % (_policy, chain_suffix)] rule += self._rich_rule_priority_fragment(rich_rule) rule += rule_fragment + [ "-j", "LOG" ] if rich_rule.log.prefix: rule += [ "--log-prefix", "'%s'" % rich_rule.log.prefix ] if rich_rule.log.level: rule += [ "--log-level", "%s" % rich_rule.log.level ] rule += self._rule_limit(rich_rule.log.limit) return rule def _rich_rule_audit(self, policy, rich_rule, enable, table, rule_fragment): if not rich_rule.audit: return [] add_del = { True: "-A", False: "-D" }[enable] _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) chain_suffix = self._rich_rule_chain_suffix_from_log(rich_rule) rule = ["-t", table, add_del, "%s_%s" % (_policy, chain_suffix)] rule += self._rich_rule_priority_fragment(rich_rule) rule += rule_fragment if type(rich_rule.action) == Rich_Accept: _type = "accept" elif type(rich_rule.action) == Rich_Reject: _type = "reject" elif type(rich_rule.action) == Rich_Drop: _type = "drop" else: _type = "unknown" rule += [ "-j", "AUDIT", "--type", _type ] rule += self._rule_limit(rich_rule.audit.limit) return rule def _rich_rule_action(self, policy, rich_rule, enable, table, rule_fragment): if not rich_rule.action: return [] add_del = { True: "-A", False: "-D" }[enable] _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) chain_suffix = self._rich_rule_chain_suffix(rich_rule) chain = "%s_%s" % (_policy, chain_suffix) if type(rich_rule.action) == Rich_Accept: rule_action = [ "-j", "ACCEPT" ] elif type(rich_rule.action) == Rich_Reject: rule_action = [ "-j", "REJECT" ] if rich_rule.action.type: rule_action += [ "--reject-with", rich_rule.action.type ] elif type(rich_rule.action) == Rich_Drop: rule_action = [ "-j", "DROP" ] elif type(rich_rule.action) == Rich_Mark: table = "mangle" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) chain = "%s_%s" % (_policy, chain_suffix) rule_action = [ "-j", "MARK", "--set-xmark", rich_rule.action.set ] else: raise FirewallError(INVALID_RULE, "Unknown action %s" % type(rich_rule.action)) rule = ["-t", table, add_del, chain] rule += self._rich_rule_priority_fragment(rich_rule) rule += rule_fragment + rule_action rule += self._rule_limit(rich_rule.action.limit) return rule def _rich_rule_destination_fragment(self, rich_dest): if not rich_dest: return [] rule_fragment = [] if rich_dest.addr: if rich_dest.invert: rule_fragment.append("!") if check_single_address("ipv6", rich_dest.addr): rule_fragment += [ "-d", normalizeIP6(rich_dest.addr) ] elif check_address("ipv6", rich_dest.addr): addr_split = rich_dest.addr.split("/") rule_fragment += [ "-d", normalizeIP6(addr_split[0]) + "/" + addr_split[1] ] else: rule_fragment += [ "-d", rich_dest.addr ] elif rich_dest.ipset: rule_fragment += [ "-m", "set" ] if rich_dest.invert: rule_fragment.append("!") flags = self._fw.zone._ipset_match_flags(rich_dest.ipset, "dst") rule_fragment += [ "--match-set", rich_dest.ipset, flags ] return rule_fragment def _rich_rule_source_fragment(self, rich_source): if not rich_source: return [] rule_fragment = [] if rich_source.addr: if rich_source.invert: rule_fragment.append("!") if check_single_address("ipv6", rich_source.addr): rule_fragment += [ "-s", normalizeIP6(rich_source.addr) ] elif check_address("ipv6", rich_source.addr): addr_split = rich_source.addr.split("/") rule_fragment += [ "-s", normalizeIP6(addr_split[0]) + "/" + addr_split[1] ] else: rule_fragment += [ "-s", rich_source.addr ] elif hasattr(rich_source, "mac") and rich_source.mac: rule_fragment += [ "-m", "mac" ] if rich_source.invert: rule_fragment.append("!") rule_fragment += [ "--mac-source", rich_source.mac ] elif hasattr(rich_source, "ipset") and rich_source.ipset: rule_fragment += [ "-m", "set" ] if rich_source.invert: rule_fragment.append("!") flags = self._fw.zone._ipset_match_flags(rich_source.ipset, "src") rule_fragment += [ "--match-set", rich_source.ipset, flags ] return rule_fragment def build_policy_ports_rules(self, enable, policy, proto, port, destination=None, rich_rule=None): add_del = { True: "-A", False: "-D" }[enable] table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) rule_fragment = [ "-p", proto ] if port: rule_fragment += [ "--dport", "%s" % portStr(port) ] if destination: rule_fragment += [ "-d", destination ] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) if not rich_rule or type(rich_rule.action) != Rich_Mark: rule_fragment += [ "-m", "conntrack", "--ctstate", "NEW,UNTRACKED" ] rules = [] if rich_rule: rules.append(self._rich_rule_log(policy, rich_rule, enable, table, rule_fragment)) rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, rule_fragment)) rules.append(self._rich_rule_action(policy, rich_rule, enable, table, rule_fragment)) else: rules.append([add_del, "%s_allow" % (_policy), "-t", table] + rule_fragment + [ "-j", "ACCEPT" ]) return rules def build_policy_protocol_rules(self, enable, policy, protocol, destination=None, rich_rule=None): add_del = { True: "-A", False: "-D" }[enable] table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) rule_fragment = [ "-p", protocol ] if destination: rule_fragment += [ "-d", destination ] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) if not rich_rule or type(rich_rule.action) != Rich_Mark: rule_fragment += [ "-m", "conntrack", "--ctstate", "NEW,UNTRACKED" ] rules = [] if rich_rule: rules.append(self._rich_rule_log(policy, rich_rule, enable, table, rule_fragment)) rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, rule_fragment)) rules.append(self._rich_rule_action(policy, rich_rule, enable, table, rule_fragment)) else: rules.append([add_del, "%s_allow" % (_policy), "-t", table] + rule_fragment + [ "-j", "ACCEPT" ]) return rules def build_policy_source_ports_rules(self, enable, policy, proto, port, destination=None, rich_rule=None): add_del = { True: "-A", False: "-D" }[enable] table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) rule_fragment = [ "-p", proto ] if port: rule_fragment += [ "--sport", "%s" % portStr(port) ] if destination: rule_fragment += [ "-d", destination ] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) if not rich_rule or type(rich_rule.action) != Rich_Mark: rule_fragment += [ "-m", "conntrack", "--ctstate", "NEW,UNTRACKED" ] rules = [] if rich_rule: rules.append(self._rich_rule_log(policy, rich_rule, enable, table, rule_fragment)) rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, rule_fragment)) rules.append(self._rich_rule_action(policy, rich_rule, enable, table, rule_fragment)) else: rules.append([add_del, "%s_allow" % (_policy), "-t", table] + rule_fragment + [ "-j", "ACCEPT" ]) return rules def build_policy_helper_ports_rules(self, enable, policy, proto, port, destination, helper_name, module_short_name): table = "raw" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "-A", False: "-D" }[enable] rule = [ add_del, "%s_allow" % (_policy), "-t", "raw", "-p", proto ] if port: rule += [ "--dport", "%s" % portStr(port) ] if destination: rule += [ "-d", destination ] rule += [ "-j", "CT", "--helper", module_short_name ] return [rule] def build_zone_forward_rules(self, enable, zone, policy, table, interface=None, source=None): add_del = { True: "-A", False: "-D" }[enable] _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) rules = [] if interface: rules.append(["-t", "filter", add_del, "%s_allow" % _policy, "-o", interface, "-j", "ACCEPT"]) else: # source # iptables can not match destination MAC if check_mac(source): return [] rules.append(["-t", "filter", add_del, "%s_allow" % _policy] + self._rule_addr_fragment("-d", source) + ["-j", "ACCEPT"]) return rules def build_policy_masquerade_rules(self, enable, policy, rich_rule=None): table = "nat" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX, isSNAT=True) add_del = { True: "-A", False: "-D" }[enable] rule_fragment = [] if rich_rule: chain_suffix = self._rich_rule_chain_suffix(rich_rule) rule_fragment += self._rich_rule_priority_fragment(rich_rule) rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) else: chain_suffix = "allow" rules = [] rules.append(["-t", "nat", add_del, "%s_%s" % (_policy, chain_suffix)] + rule_fragment + [ "!", "-o", "lo", "-j", "MASQUERADE" ]) rule_fragment = [] if rich_rule: chain_suffix = self._rich_rule_chain_suffix(rich_rule) rule_fragment += self._rich_rule_priority_fragment(rich_rule) rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) else: chain_suffix = "allow" table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) rules.append(["-t", "filter", add_del, "%s_%s" % (_policy, chain_suffix)] + rule_fragment + ["-m", "conntrack", "--ctstate", "NEW,UNTRACKED", "-j", "ACCEPT" ]) return rules def build_policy_forward_port_rules(self, enable, policy, port, protocol, toport, toaddr, rich_rule=None): table = "nat" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "-A", False: "-D" }[enable] to = "" if toaddr: if check_single_address("ipv6", toaddr): to += "[%s]" % normalizeIP6(toaddr) else: to += toaddr if toport and toport != "": to += ":%s" % portStr(toport, "-") rule_fragment = [] if rich_rule: chain_suffix = self._rich_rule_chain_suffix(rich_rule) rule_fragment = self._rich_rule_priority_fragment(rich_rule) rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) else: chain_suffix = "allow" rules = [] if rich_rule: rules.append(self._rich_rule_log(policy, rich_rule, enable, "nat", rule_fragment)) rules.append(["-t", "nat", add_del, "%s_%s" % (_policy, chain_suffix)] + rule_fragment + ["-p", protocol, "--dport", portStr(port), "-j", "DNAT", "--to-destination", to]) return rules def build_policy_icmp_block_rules(self, enable, policy, ict, rich_rule=None): table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) add_del = { True: "-A", False: "-D" }[enable] if self.ipv == "ipv4": proto = [ "-p", "icmp" ] match = [ "-m", "icmp", "--icmp-type", ict.name ] else: proto = [ "-p", "ipv6-icmp" ] match = [ "-m", "icmp6", "--icmpv6-type", ict.name ] rules = [] if self._fw.policy.query_icmp_block_inversion(policy): final_chain = "%s_allow" % (_policy) final_target = "ACCEPT" else: final_chain = "%s_deny" % (_policy) final_target = "%%REJECT%%" rule_fragment = [] if rich_rule: rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rule_fragment += proto + match if rich_rule: rules.append(self._rich_rule_log(policy, rich_rule, enable, table, rule_fragment)) rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, rule_fragment)) if rich_rule.action: rules.append(self._rich_rule_action(policy, rich_rule, enable, table, rule_fragment)) else: chain_suffix = self._rich_rule_chain_suffix(rich_rule) rules.append(["-t", table, add_del, "%s_%s" % (_policy, chain_suffix)] + self._rich_rule_priority_fragment(rich_rule) + rule_fragment + [ "-j", "%%REJECT%%" ]) else: if self._fw.get_log_denied() != "off" and final_target != "ACCEPT": rules.append([ add_del, final_chain, "-t", table ] + rule_fragment + [ "%%LOGTYPE%%", "-j", "LOG", "--log-prefix", "\"%s_ICMP_BLOCK: \"" % policy ]) rules.append([ add_del, final_chain, "-t", table ] + rule_fragment + [ "-j", final_target ]) return rules def build_policy_icmp_block_inversion_rules(self, enable, policy): table = "filter" _policy = self._fw.policy.policy_base_chain_name(policy, table, POLICY_CHAIN_PREFIX) rules = [] rule_idx = 6 if self._fw.policy.query_icmp_block_inversion(policy): ibi_target = "%%REJECT%%" if self._fw.get_log_denied() != "off": if enable: rule = [ "-I", _policy, str(rule_idx) ] else: rule = [ "-D", _policy ] rule = rule + [ "-t", table, "-p", "%%ICMP%%", "%%LOGTYPE%%", "-j", "LOG", "--log-prefix", "\"%s_ICMP_BLOCK: \"" % _policy ] rules.append(rule) rule_idx += 1 else: ibi_target = "ACCEPT" if enable: rule = [ "-I", _policy, str(rule_idx) ] else: rule = [ "-D", _policy ] rule = rule + [ "-t", table, "-p", "%%ICMP%%", "-j", ibi_target ] rules.append(rule) return rules def build_policy_rich_source_destination_rules(self, enable, policy, rich_rule): table = "filter" rule_fragment = [] rule_fragment += self._rich_rule_destination_fragment(rich_rule.destination) rule_fragment += self._rich_rule_source_fragment(rich_rule.source) rules = [] rules.append(self._rich_rule_log(policy, rich_rule, enable, table, rule_fragment)) rules.append(self._rich_rule_audit(policy, rich_rule, enable, table, rule_fragment)) rules.append(self._rich_rule_action(policy, rich_rule, enable, table, rule_fragment)) return rules def is_ipv_supported(self, ipv): return ipv == self.ipv class ip6tables(ip4tables): ipv = "ipv6" name = "ip6tables" def build_rpfilter_rules(self, log_denied=False): rules = [] rules.append([ "-I", "PREROUTING", "-t", "mangle", "-m", "rpfilter", "--invert", "--validmark", "-j", "DROP" ]) if log_denied != "off": rules.append([ "-I", "PREROUTING", "-t", "mangle", "-m", "rpfilter", "--invert", "--validmark", "-j", "LOG", "--log-prefix", "rpfilter_DROP: " ]) rules.append([ "-I", "PREROUTING", "-t", "mangle", "-p", "ipv6-icmp", "--icmpv6-type=neighbour-solicitation", "-j", "ACCEPT" ]) # RHBZ#1575431, kernel bug in 4.16-4.17 rules.append([ "-I", "PREROUTING", "-t", "mangle", "-p", "ipv6-icmp", "--icmpv6-type=router-advertisement", "-j", "ACCEPT" ]) # RHBZ#1058505 return rules def build_rfc3964_ipv4_rules(self): daddr_list = [ "::0.0.0.0/96", # IPv4 compatible "::ffff:0.0.0.0/96", # IPv4 mapped "2002:0000::/24", # 0.0.0.0/8 (the system has no address assigned yet) "2002:0a00::/24", # 10.0.0.0/8 (private) "2002:7f00::/24", # 127.0.0.0/8 (loopback) "2002:ac10::/28", # 172.16.0.0/12 (private) "2002:c0a8::/32", # 192.168.0.0/16 (private) "2002:a9fe::/32", # 169.254.0.0/16 (IANA Assigned DHCP link-local) "2002:e000::/19", # 224.0.0.0/4 (multicast), 240.0.0.0/4 (reserved and broadcast) ] chain_name = "RFC3964_IPv4" self.our_chains["filter"].add(chain_name) rules = [] rules.append(["-t", "filter", "-N", chain_name]) for daddr in daddr_list: rules.append(["-t", "filter", "-I", chain_name, "-d", daddr, "-j", "REJECT", "--reject-with", "addr-unreach"]) if self._fw._log_denied in ["unicast", "all"]: rules.append(["-t", "filter", "-I", chain_name, "-d", daddr, "-j", "LOG", "--log-prefix", "\"RFC3964_IPv4_REJECT: \""]) # Inject into FORWARD and OUTPUT chains rules.append(["-t", "filter", "-I", "OUTPUT", "4", "-j", chain_name]) rules.append(["-t", "filter", "-I", "FORWARD", "4", "-j", chain_name]) return rules PKpge[~ watcher.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2012-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "Watcher" ] from gi.repository import Gio, GLib class Watcher(object): def __init__(self, callback, timeout): self._callback = callback self._timeout = timeout self._monitors = { } self._timeouts = { } self._blocked = [ ] def add_watch_dir(self, directory): gfile = Gio.File.new_for_path(directory) self._monitors[directory] = gfile.monitor_directory(\ Gio.FileMonitorFlags.NONE, None) self._monitors[directory].connect("changed", self._file_changed_cb) def add_watch_file(self, filename): gfile = Gio.File.new_for_path(filename) self._monitors[filename] = gfile.monitor_file(\ Gio.FileMonitorFlags.NONE, None) self._monitors[filename].connect("changed", self._file_changed_cb) def get_watches(self): return self._monitors.keys() def has_watch(self, filename): return filename in self._monitors def remove_watch(self, filename): del self._monitors[filename] def block_source(self, filename): if filename not in self._blocked: self._blocked.append(filename) def unblock_source(self, filename): if filename in self._blocked: self._blocked.remove(filename) def clear_timeouts(self): for filename in list(self._timeouts.keys()): GLib.source_remove(self._timeouts[filename]) del self._timeouts[filename] def _call_callback(self, filename): if filename not in self._blocked: self._callback(filename) del self._timeouts[filename] def _file_changed_cb(self, monitor, gio_file, gio_other_file, event): filename = gio_file.get_parse_name() if filename in self._blocked: if filename in self._timeouts: GLib.source_remove(self._timeouts[filename]) del self._timeouts[filename] return if event == Gio.FileMonitorEvent.CHANGED or \ event == Gio.FileMonitorEvent.CREATED or \ event == Gio.FileMonitorEvent.DELETED or \ event == Gio.FileMonitorEvent.ATTRIBUTE_CHANGED: if filename in self._timeouts: GLib.source_remove(self._timeouts[filename]) del self._timeouts[filename] self._timeouts[filename] = GLib.timeout_add_seconds(\ self._timeout, self._call_callback, filename) PKpge[OXWW fw_direct.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "FirewallDirect" ] from firewall.fw_types import LastUpdatedOrderedDict from firewall.core import ipXtables from firewall.core import ebtables from firewall.core.fw_transaction import FirewallTransaction from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError ############################################################################ # # class Firewall # ############################################################################ class FirewallDirect(object): def __init__(self, fw): self._fw = fw self.__init_vars() def __repr__(self): return '%s(%r, %r, %r)' % (self.__class__, self._chains, self._rules, self._rule_priority_positions) def __init_vars(self): self._chains = { } self._rules = { } self._rule_priority_positions = { } self._passthroughs = { } self._obj = None def cleanup(self): self.__init_vars() # transaction def new_transaction(self): return FirewallTransaction(self._fw) # configuration def set_permanent_config(self, obj): self._obj = obj def has_runtime_configuration(self): if len(self._chains) + len(self._rules) + len(self._passthroughs) > 0: return True return False def has_configuration(self): if self.has_runtime_configuration(): return True if len(self._obj.get_all_chains()) + \ len(self._obj.get_all_rules()) + \ len(self._obj.get_all_passthroughs()) > 0: return True return False def apply_direct(self, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction # Apply permanent configuration and save the obj to be able to # remove permanent configuration settings within get_runtime_config # for use in firewalld reload. self.set_config((self._obj.get_all_chains(), self._obj.get_all_rules(), self._obj.get_all_passthroughs()), transaction) if use_transaction is None: transaction.execute(True) def get_runtime_config(self): # Return only runtime changes # Remove all chains, rules and passthroughs that are in self._obj # (permanent config applied in firewalld _start. chains = { } rules = { } passthroughs = { } for table_id in self._chains: (ipv, table) = table_id for chain in self._chains[table_id]: if not self._obj.query_chain(ipv, table, chain): chains.setdefault(table_id, [ ]).append(chain) for chain_id in self._rules: (ipv, table, chain) = chain_id for (priority, args) in self._rules[chain_id]: if not self._obj.query_rule(ipv, table, chain, priority, args): if chain_id not in rules: rules[chain_id] = LastUpdatedOrderedDict() rules[chain_id][(priority, args)] = priority for ipv in self._passthroughs: for args in self._passthroughs[ipv]: if not self._obj.query_passthrough(ipv, args): if ipv not in passthroughs: passthroughs[ipv] = [ ] passthroughs[ipv].append(args) return (chains, rules, passthroughs) def get_config(self): return (self._chains, self._rules, self._passthroughs) def set_config(self, conf, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction (_chains, _rules, _passthroughs) = conf for table_id in _chains: (ipv, table) = table_id for chain in _chains[table_id]: if not self.query_chain(ipv, table, chain): try: self.add_chain(ipv, table, chain, use_transaction=transaction) except FirewallError as error: log.warning(str(error)) for chain_id in _rules: (ipv, table, chain) = chain_id for (priority, args) in _rules[chain_id]: if not self.query_rule(ipv, table, chain, priority, args): try: self.add_rule(ipv, table, chain, priority, args, use_transaction=transaction) except FirewallError as error: log.warning(str(error)) for ipv in _passthroughs: for args in _passthroughs[ipv]: if not self.query_passthrough(ipv, args): try: self.add_passthrough(ipv, args, use_transaction=transaction) except FirewallError as error: log.warning(str(error)) if use_transaction is None: transaction.execute(True) def _check_ipv(self, ipv): ipvs = ['ipv4', 'ipv6', 'eb'] if ipv not in ipvs: raise FirewallError(errors.INVALID_IPV, "'%s' not in '%s'" % (ipv, ipvs)) def _check_ipv_table(self, ipv, table): self._check_ipv(ipv) tables = ipXtables.BUILT_IN_CHAINS.keys() if ipv in [ 'ipv4', 'ipv6' ] \ else ebtables.BUILT_IN_CHAINS.keys() if table not in tables: raise FirewallError(errors.INVALID_TABLE, "'%s' not in '%s'" % (table, tables)) def _check_builtin_chain(self, ipv, table, chain): if ipv in ['ipv4', 'ipv6']: built_in_chains = ipXtables.BUILT_IN_CHAINS[table] if self._fw.nftables_enabled: our_chains = {} else: our_chains = self._fw.get_direct_backend_by_ipv(ipv).our_chains[table] else: built_in_chains = ebtables.BUILT_IN_CHAINS[table] our_chains = ebtables.OUR_CHAINS[table] if chain in built_in_chains: raise FirewallError(errors.BUILTIN_CHAIN, "chain '%s' is built-in chain" % chain) if chain in our_chains: raise FirewallError(errors.BUILTIN_CHAIN, "chain '%s' is reserved" % chain) if ipv in [ "ipv4", "ipv6" ]: if self._fw.zone.zone_from_chain(chain) is not None: raise FirewallError(errors.INVALID_CHAIN, "Chain '%s' is reserved" % chain) def _register_chain(self, table_id, chain, add): if add: self._chains.setdefault(table_id, [ ]).append(chain) else: self._chains[table_id].remove(chain) if len(self._chains[table_id]) == 0: del self._chains[table_id] def add_chain(self, ipv, table, chain, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if self._fw.may_skip_flush_direct_backends(): transaction.add_pre(self._fw.flush_direct_backends) #TODO: policy="ACCEPT" self._chain(True, ipv, table, chain, transaction) if use_transaction is None: transaction.execute(True) def remove_chain(self, ipv, table, chain, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self._chain(False, ipv, table, chain, transaction) if use_transaction is None: transaction.execute(True) def query_chain(self, ipv, table, chain): self._check_ipv_table(ipv, table) self._check_builtin_chain(ipv, table, chain) table_id = (ipv, table) return (table_id in self._chains and chain in self._chains[table_id]) def get_chains(self, ipv, table): self._check_ipv_table(ipv, table) table_id = (ipv, table) if table_id in self._chains: return self._chains[table_id] return [ ] def get_all_chains(self): r = [ ] for key in self._chains: (ipv, table) = key for chain in self._chains[key]: r.append((ipv, table, chain)) return r def add_rule(self, ipv, table, chain, priority, args, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if self._fw.may_skip_flush_direct_backends(): transaction.add_pre(self._fw.flush_direct_backends) self._rule(True, ipv, table, chain, priority, args, transaction) if use_transaction is None: transaction.execute(True) def remove_rule(self, ipv, table, chain, priority, args, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self._rule(False, ipv, table, chain, priority, args, transaction) if use_transaction is None: transaction.execute(True) def query_rule(self, ipv, table, chain, priority, args): self._check_ipv_table(ipv, table) chain_id = (ipv, table, chain) return chain_id in self._rules and \ (priority, args) in self._rules[chain_id] def get_rules(self, ipv, table, chain): self._check_ipv_table(ipv, table) chain_id = (ipv, table, chain) if chain_id in self._rules: return list(self._rules[chain_id].keys()) return [ ] def get_all_rules(self): r = [ ] for key in self._rules: (ipv, table, chain) = key for (priority, args) in self._rules[key]: r.append((ipv, table, chain, priority, list(args))) return r def _register_rule(self, rule_id, chain_id, priority, enable, count): if enable: if chain_id not in self._rules: self._rules[chain_id] = LastUpdatedOrderedDict() self._rules[chain_id][rule_id] = priority if chain_id not in self._rule_priority_positions: self._rule_priority_positions[chain_id] = { } if priority in self._rule_priority_positions[chain_id]: self._rule_priority_positions[chain_id][priority] += count else: self._rule_priority_positions[chain_id][priority] = count else: del self._rules[chain_id][rule_id] if len(self._rules[chain_id]) == 0: del self._rules[chain_id] self._rule_priority_positions[chain_id][priority] -= count # DIRECT PASSTHROUGH (untracked) def passthrough(self, ipv, args): try: return self._fw.rule(self._fw.get_direct_backend_by_ipv(ipv).name, args) except Exception as msg: log.debug2(msg) raise FirewallError(errors.COMMAND_FAILED, msg) def _register_passthrough(self, ipv, args, enable): if enable: if ipv not in self._passthroughs: self._passthroughs[ipv] = [ ] self._passthroughs[ipv].append(args) else: self._passthroughs[ipv].remove(args) if len(self._passthroughs[ipv]) == 0: del self._passthroughs[ipv] def add_passthrough(self, ipv, args, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction if self._fw.may_skip_flush_direct_backends(): transaction.add_pre(self._fw.flush_direct_backends) self._passthrough(True, ipv, list(args), transaction) if use_transaction is None: transaction.execute(True) def remove_passthrough(self, ipv, args, use_transaction=None): if use_transaction is None: transaction = self.new_transaction() else: transaction = use_transaction self._passthrough(False, ipv, list(args), transaction) if use_transaction is None: transaction.execute(True) def query_passthrough(self, ipv, args): return ipv in self._passthroughs and \ tuple(args) in self._passthroughs[ipv] def get_all_passthroughs(self): r = [ ] for ipv in self._passthroughs: for args in self._passthroughs[ipv]: r.append((ipv, list(args))) return r def get_passthroughs(self, ipv): r = [ ] if ipv in self._passthroughs: for args in self._passthroughs[ipv]: r.append(list(args)) return r def split_value(self, rules, opts): """Split values combined with commas for options in opts""" out_rules = [ ] for rule in rules: processed = False for opt in opts: try: i = rule.index(opt) except ValueError: pass else: if len(rule) > i and "," in rule[i+1]: # For all items in the comma separated list in index # i of the rule, a new rule is created with a single # item from this list processed = True items = rule[i+1].split(",") for item in items: _rule = rule[:] _rule[i+1] = item out_rules.append(_rule) if not processed: out_rules.append(rule) return out_rules def _rule(self, enable, ipv, table, chain, priority, args, transaction): self._check_ipv_table(ipv, table) # Do not create zone chains if we're using nftables. Only allow direct # rules in the built in chains. if not self._fw.nftables_enabled \ and ipv in [ "ipv4", "ipv6" ]: self._fw.zone.create_zone_base_by_chain(ipv, table, chain, transaction) _chain = chain backend = self._fw.get_direct_backend_by_ipv(ipv) # if nftables is in use, just put the direct rules in the chain # specified by the user. i.e. don't append _direct. if not self._fw.nftables_enabled \ and backend.is_chain_builtin(ipv, table, chain): _chain = "%s_direct" % (chain) elif self._fw.nftables_enabled and chain[-7:] == "_direct" \ and backend.is_chain_builtin(ipv, table, chain[:-7]): # strip _direct suffix. If we're using nftables we don't bother # creating the *_direct chains for builtin chains. _chain = chain[:-7] chain_id = (ipv, table, chain) rule_id = (priority, args) if enable: if chain_id in self._rules and \ rule_id in self._rules[chain_id]: raise FirewallError(errors.ALREADY_ENABLED, "rule '%s' already is in '%s:%s:%s'" % \ (args, ipv, table, chain)) else: if chain_id not in self._rules or \ rule_id not in self._rules[chain_id]: raise FirewallError(errors.NOT_ENABLED, "rule '%s' is not in '%s:%s:%s'" % \ (args, ipv, table, chain)) # get priority of rule priority = self._rules[chain_id][rule_id] # If a rule gets added, the initial rule index position within the # ipv, table and chain combination (chain_id) is 1. # Tf the chain_id exists in _rule_priority_positions, there are already # other rules for this chain_id. The number of rules for a priority # less or equal to the priority of the new rule will increase the # index of the new rule. The index is the ip*tables -I insert rule # number. # # Example: We have the following rules for chain_id (ipv4, filter, # INPUT) already: # ipv4, filter, INPUT, 1, -i, foo1, -j, ACCEPT # ipv4, filter, INPUT, 2, -i, foo2, -j, ACCEPT # ipv4, filter, INPUT, 2, -i, foo2_1, -j, ACCEPT # ipv4, filter, INPUT, 3, -i, foo3, -j, ACCEPT # This results in the following _rule_priority_positions structure: # _rule_priority_positions[(ipv4,filter,INPUT)][1] = 1 # _rule_priority_positions[(ipv4,filter,INPUT)][2] = 2 # _rule_priority_positions[(ipv4,filter,INPUT)][3] = 1 # The new rule # ipv4, filter, INPUT, 2, -i, foo2_2, -j, ACCEPT # has the same pritority as the second rule before and will be added # right after it. # The initial index is 1 and the chain_id is already in # _rule_priority_positions. Therefore the index will increase for # the number of rules in every rule position in # _rule_priority_positions[(ipv4,filter,INPUT)].keys() # where position is smaller or equal to the entry in keys. # With the example from above: # The priority of the new rule is 2. Therefore for all keys in # _rule_priority_positions[chain_id] where priority is 1 or 2, the # number of the rules will increase the index of the rule. # For _rule_priority_positions[chain_id][1]: index += 1 # _rule_priority_positions[chain_id][2]: index += 2 # index will be 4 in the end and the rule in the table chain # combination will be added at index 4. # If there are no rules in the table chain combination, a new rule # has index 1. index = 1 count = 0 if chain_id in self._rule_priority_positions: positions = sorted(self._rule_priority_positions[chain_id].keys()) j = 0 while j < len(positions) and priority >= positions[j]: index += self._rule_priority_positions[chain_id][positions[j]] j += 1 # split the direct rule in some cases as iptables-restore can't handle # compound args. # args_list = [list(args)] args_list = self.split_value(args_list, [ "-s", "--source" ]) args_list = self.split_value(args_list, [ "-d", "--destination" ]) for _args in args_list: transaction.add_rule(backend, backend.build_rule(enable, table, _chain, index, tuple(_args))) index += 1 count += 1 self._register_rule(rule_id, chain_id, priority, enable, count) transaction.add_fail(self._register_rule, rule_id, chain_id, priority, not enable, count) def _chain(self, add, ipv, table, chain, transaction): self._check_ipv_table(ipv, table) self._check_builtin_chain(ipv, table, chain) table_id = (ipv, table) if add: if table_id in self._chains and \ chain in self._chains[table_id]: raise FirewallError(errors.ALREADY_ENABLED, "chain '%s' already is in '%s:%s'" % \ (chain, ipv, table)) else: if table_id not in self._chains or \ chain not in self._chains[table_id]: raise FirewallError(errors.NOT_ENABLED, "chain '%s' is not in '%s:%s'" % \ (chain, ipv, table)) backend = self._fw.get_direct_backend_by_ipv(ipv) transaction.add_rules(backend, backend.build_chain_rules(add, table, chain)) self._register_chain(table_id, chain, add) transaction.add_fail(self._register_chain, table_id, chain, not add) def _passthrough(self, enable, ipv, args, transaction): self._check_ipv(ipv) tuple_args = tuple(args) if enable: if ipv in self._passthroughs and \ tuple_args in self._passthroughs[ipv]: raise FirewallError(errors.ALREADY_ENABLED, "passthrough '%s', '%s'" % (ipv, args)) else: if ipv not in self._passthroughs or \ tuple_args not in self._passthroughs[ipv]: raise FirewallError(errors.NOT_ENABLED, "passthrough '%s', '%s'" % (ipv, args)) backend = self._fw.get_direct_backend_by_ipv(ipv) if enable: backend.check_passthrough(args) # try to find out if a zone chain should be used if ipv in [ "ipv4", "ipv6" ]: table, chain = backend.passthrough_parse_table_chain(args) if table and chain: self._fw.zone.create_zone_base_by_chain(ipv, table, chain) _args = args else: _args = backend.reverse_passthrough(args) transaction.add_rule(backend, _args) self._register_passthrough(ipv, tuple_args, enable) transaction.add_fail(self._register_passthrough, ipv, tuple_args, not enable) PKpge[  icmp.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2017 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "ICMP_TYPES", "ICMPV6_TYPES", "check_icmp_type", "check_icmpv6_type" ] ICMP_TYPES = { "echo-reply": "0/0", "pong": "0/0", "network-unreachable": "3/0", "host-unreachable": "3/1", "protocol-unreachable": "3/2", "port-unreachable": "3/3", "fragmentation-needed": "3/4", "source-route-failed": "3/5", "network-unknown": "3/6", "host-unknown": "3/7", "network-prohibited": "3/9", "host-prohibited": "3/10", "TOS-network-unreachable": "3/11", "TOS-host-unreachable": "3/12", "communication-prohibited": "3/13", "host-precedence-violation": "3/14", "precedence-cutoff": "3/15", "source-quench": "4/0", "network-redirect": "5/0", "host-redirect": "5/1", "TOS-network-redirect": "5/2", "TOS-host-redirect": "5/3", "echo-request": "8/0", "ping": "8/0", "router-advertisement": "9/0", "router-solicitation": "10/0", "ttl-zero-during-transit": "11/0", "ttl-zero-during-reassembly": "11/1", "ip-header-bad": "12/0", "required-option-missing": "12/1", "timestamp-request": "13/0", "timestamp-reply": "14/0", "address-mask-request": "17/0", "address-mask-reply": "18/0", } ICMPV6_TYPES = { "no-route": "1/0", "communication-prohibited": "1/1", "address-unreachable": "1/3", "port-unreachable": "1/4", "packet-too-big": "2/0", "ttl-zero-during-transit": "3/0", "ttl-zero-during-reassembly": "3/1", "bad-header": "4/0", "unknown-header-type": "4/1", "unknown-option": "4/2", "echo-request": "128/0", "ping": "128/0", "echo-reply": "129/0", "pong": "129/0", "router-solicitation": "133/0", "router-advertisement": "134/0", "neighbour-solicitation": "135/0", "neigbour-solicitation": "135/0", "neighbour-advertisement": "136/0", "neigbour-advertisement": "136/0", "redirect": "137/0", } def check_icmp_name(_name): if _name in ICMP_TYPES: return True return False def check_icmp_type(_type): if _type in ICMP_TYPES.values(): return True return False def check_icmpv6_name(_name): if _name in ICMP_TYPES: return True return False def check_icmpv6_type(_type): if _type in ICMPV6_TYPES.values(): return True return False PKpge[^ܪ>y>y logger.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2005-2007,2012 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "LogTarget", "FileLog", "Logger", "log" ] import sys import types import time import inspect import fnmatch import syslog import traceback import fcntl import os.path import os # --------------------------------------------------------------------------- # abstract class for logging targets class LogTarget(object): """ Abstract class for logging targets. """ def __init__(self): self.fd = None def write(self, data, level, logger, is_debug=0): raise NotImplementedError("LogTarget.write is an abstract method") def flush(self): raise NotImplementedError("LogTarget.flush is an abstract method") def close(self): raise NotImplementedError("LogTarget.close is an abstract method") # --------------------------------------------------------------------------- # private class for stdout class _StdoutLog(LogTarget): def __init__(self): LogTarget.__init__(self) self.fd = sys.stdout def write(self, data, level, logger, is_debug=0): # ignore level self.fd.write(data) self.flush() def close(self): self.flush() def flush(self): self.fd.flush() # --------------------------------------------------------------------------- # private class for stderr class _StderrLog(_StdoutLog): def __init__(self): _StdoutLog.__init__(self) self.fd = sys.stderr # --------------------------------------------------------------------------- # private class for syslog class _SyslogLog(LogTarget): def __init__(self): # Only initialize LogTarget here as fs should be None LogTarget.__init__(self) # # Derived from: https://github.com/canvon/firewalld/commit/af0edfee1cc1891b7b13f302ca5911b24e9b0f13 # # Work around Python issue 27875, "Syslogs /usr/sbin/foo as /foo # instead of as foo" # (but using openlog explicitly might be better anyway) # # Set ident to basename, log PID as well, and log to facility "daemon". syslog.openlog(os.path.basename(sys.argv[0]), syslog.LOG_PID, syslog.LOG_DAEMON) def write(self, data, level, logger, is_debug=0): priority = None if is_debug: priority = syslog.LOG_DEBUG else: if level >= logger.INFO1: priority = syslog.LOG_INFO elif level == logger.WARNING: priority = syslog.LOG_WARNING elif level == logger.ERROR: priority = syslog.LOG_ERR elif level == logger.FATAL: priority = syslog.LOG_CRIT if data.endswith("\n"): data = data[:len(data)-1] if len(data) > 0: if priority is None: syslog.syslog(data) else: syslog.syslog(priority, data) def close(self): syslog.closelog() def flush(self): pass # --------------------------------------------------------------------------- class FileLog(LogTarget): """ FileLog class. File will be opened on the first write. """ def __init__(self, filename, mode="w"): LogTarget.__init__(self) self.filename = filename self.mode = mode def open(self): if self.fd: return flags = os.O_CREAT | os.O_WRONLY if self.mode.startswith('a'): flags |= os.O_APPEND self.fd = os.open(self.filename, flags, 0o640) # Make sure that existing file has correct perms os.fchmod(self.fd, 0o640) # Make it an object self.fd = os.fdopen(self.fd, self.mode) fcntl.fcntl(self.fd, fcntl.F_SETFD, fcntl.FD_CLOEXEC) def write(self, data, level, logger, is_debug=0): if not self.fd: self.open() self.fd.write(data) self.fd.flush() def close(self): if not self.fd: return self.fd.close() self.fd = None def flush(self): if not self.fd: return self.fd.flush() # --------------------------------------------------------------------------- class Logger(object): r""" Format string: %(class)s Calling class the function belongs to, else empty %(date)s Date using Logger.date_format, see time module %(domain)s Full Domain: %(module)s.%(class)s.%(function)s %(file)s Filename of the module %(function)s Function name, empty in __main__ %(label)s Label according to log function call from Logger.label %(level)d Internal logging level %(line)d Line number in module %(module)s Module name %(message)s Log message Standard levels: FATAL Fatal error messages ERROR Error messages WARNING Warning messages INFOx, x in [1..5] Information DEBUGy, y in [1..10] Debug messages NO_INFO No info output NO_DEBUG No debug output INFO_MAX Maximum info level DEBUG_MAX Maximum debug level x and y depend on info_max and debug_max from Logger class initialization. See __init__ function. Default logging targets: stdout Logs to stdout stderr Logs to stderr syslog Logs to syslog Additional arguments for logging functions (fatal, error, warning, info and debug): nl Disable newline at the end with nl=0, default is nl=1. fmt Format string for this logging entry, overloads global format string. Example: fmt="%(file)s:%(line)d %(message)s" nofmt Only output message with nofmt=1. The nofmt argument wins over the fmt argument. Example: from logger import log log.setInfoLogLevel(log.INFO1) log.setDebugLogLevel(log.DEBUG1) for i in range(1, log.INFO_MAX+1): log.setInfoLogLabel(i, "INFO%d: " % i) log.setFormat("%(date)s %(module)s:%(line)d [%(domain)s] %(label)s: " "%(level)d %(message)s") log.setDateFormat("%Y-%m-%d %H:%M:%S") fl = FileLog("/tmp/log", "a") log.addInfoLogging("*", fl) log.addDebugLogging("*", fl) log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s") log.debug3("debug3") log.debug2("debug2") log.debug1("debug1") log.info2("info2") log.info1("info1") log.warning("warning\n", nl=0) log.error("error\n", nl=0) log.fatal("fatal") log.info(log.INFO1, "nofmt info", nofmt=1) """ ALL = -5 NOTHING = -4 FATAL = -3 TRACEBACK = -2 ERROR = -1 WARNING = 0 # Additional levels are generated in class initilization stdout = _StdoutLog() stderr = _StderrLog() syslog = _SyslogLog() def __init__(self, info_max=5, debug_max=10): """ Logger class initialization """ self._level = { } self._debug_level = { } self._format = "" self._date_format = "" self._label = { } self._debug_label = { } self._logging = { } self._debug_logging = { } self._domains = { } self._debug_domains = { } # INFO1 is required for standard log level if info_max < 1: raise ValueError("Logger: info_max %d is too low" % info_max) if debug_max < 0: raise ValueError("Logger: debug_max %d is too low" % debug_max) self.NO_INFO = self.WARNING # = 0 self.INFO_MAX = info_max self.NO_DEBUG = 0 self.DEBUG_MAX = debug_max self.setInfoLogLabel(self.FATAL, "FATAL ERROR: ") self.setInfoLogLabel(self.TRACEBACK, "") self.setInfoLogLabel(self.ERROR, "ERROR: ") self.setInfoLogLabel(self.WARNING, "WARNING: ") # generate info levels and infox functions for _level in range(1, self.INFO_MAX+1): setattr(self, "INFO%d" % _level, _level) self.setInfoLogLabel(_level, "") setattr(self, "info%d" % (_level), (lambda self, x: lambda message, *args, **kwargs: self.info(x, message, *args, **kwargs))(self, _level)) # pylint: disable=E0602 # generate debug levels and debugx functions for _level in range(1, self.DEBUG_MAX+1): setattr(self, "DEBUG%d" % _level, _level) self.setDebugLogLabel(_level, "DEBUG%d: " % _level) setattr(self, "debug%d" % (_level), (lambda self, x: lambda message, *args, **kwargs: self.debug(x, message, *args, **kwargs))(self, _level)) # pylint: disable=E0602 # set initial log levels, formats and targets self.setInfoLogLevel(self.INFO1) self.setDebugLogLevel(self.NO_DEBUG) self.setFormat("%(label)s%(message)s") self.setDateFormat("%d %b %Y %H:%M:%S") self.setInfoLogging("*", self.stderr, [ self.FATAL, self.ERROR, self.WARNING ]) self.setInfoLogging("*", self.stdout, [ i for i in range(self.INFO1, self.INFO_MAX+1) ]) self.setDebugLogging("*", self.stdout, [ i for i in range(1, self.DEBUG_MAX+1) ]) def close(self): """ Close all logging targets """ for level in range(self.FATAL, self.DEBUG_MAX+1): if level not in self._logging: continue for (dummy, target, dummy) in self._logging[level]: target.close() def getInfoLogLevel(self, domain="*"): """ Get info log level. """ self._checkDomain(domain) if domain in self._level: return self._level[domain] return self.NOTHING def setInfoLogLevel(self, level, domain="*"): """ Set log level [NOTHING .. INFO_MAX] """ self._checkDomain(domain) if level < self.NOTHING: level = self.NOTHING if level > self.INFO_MAX: level = self.INFO_MAX self._level[domain] = level def getDebugLogLevel(self, domain="*"): """ Get debug log level. """ self._checkDomain(domain) if domain in self._debug_level: return self._debug_level[domain] + self.NO_DEBUG return self.NO_DEBUG def setDebugLogLevel(self, level, domain="*"): """ Set debug log level [NO_DEBUG .. DEBUG_MAX] """ self._checkDomain(domain) if level < 0: level = 0 if level > self.DEBUG_MAX: level = self.DEBUG_MAX self._debug_level[domain] = level - self.NO_DEBUG def getFormat(self): return self._format def setFormat(self, _format): self._format = _format def getDateFormat(self): return self._date_format def setDateFormat(self, _format): self._date_format = _format def setInfoLogLabel(self, level, label): """ Set log label for level. Level can be a single level or an array of levels. """ levels = self._getLevels(level) for level in levels: self._checkLogLevel(level, min_level=self.FATAL, max_level=self.INFO_MAX) self._label[level] = label def setDebugLogLabel(self, level, label): """ Set log label for level. Level can be a single level or an array of levels. """ levels = self._getLevels(level, is_debug=1) for level in levels: self._checkLogLevel(level, min_level=self.INFO1, max_level=self.DEBUG_MAX) self._debug_label[level] = label def setInfoLogging(self, domain, target, level=ALL, fmt=None): """ Set info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._setLogging(domain, target, level, fmt, is_debug=0) def setDebugLogging(self, domain, target, level=ALL, fmt=None): """ Set debug log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._setLogging(domain, target, level, fmt, is_debug=1) def addInfoLogging(self, domain, target, level=ALL, fmt=None): """ Add info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._addLogging(domain, target, level, fmt, is_debug=0) def addDebugLogging(self, domain, target, level=ALL, fmt=None): """ Add debg log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._addLogging(domain, target, level, fmt, is_debug=1) def delInfoLogging(self, domain, target, level=ALL, fmt=None): """ Delete info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._delLogging(domain, target, level, fmt, is_debug=0) def delDebugLogging(self, domain, target, level=ALL, fmt=None): """ Delete debug log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. """ self._delLogging(domain, target, level, fmt, is_debug=1) def isInfoLoggingHere(self, level): """ Is there currently any info logging for this log level (and domain)? """ return self._isLoggingHere(level, is_debug=0) def isDebugLoggingHere(self, level): """ Is there currently any debug logging for this log level (and domain)? """ return self._isLoggingHere(level, is_debug=1) ### log functions def fatal(self, _format, *args, **kwargs): """ Fatal error log. """ self._checkKWargs(kwargs) kwargs["is_debug"] = 0 self._log(self.FATAL, _format, *args, **kwargs) def error(self, _format, *args, **kwargs): """ Error log. """ self._checkKWargs(kwargs) kwargs["is_debug"] = 0 self._log(self.ERROR, _format, *args, **kwargs) def warning(self, _format, *args, **kwargs): """ Warning log. """ self._checkKWargs(kwargs) kwargs["is_debug"] = 0 self._log(self.WARNING, _format, *args, **kwargs) def info(self, level, _format, *args, **kwargs): """ Information log using info level [1..info_max]. There are additional infox functions according to info_max from __init__""" self._checkLogLevel(level, min_level=1, max_level=self.INFO_MAX) self._checkKWargs(kwargs) kwargs["is_debug"] = 0 self._log(level+self.NO_INFO, _format, *args, **kwargs) def debug(self, level, _format, *args, **kwargs): """ Debug log using debug level [1..debug_max]. There are additional debugx functions according to debug_max from __init__""" self._checkLogLevel(level, min_level=1, max_level=self.DEBUG_MAX) self._checkKWargs(kwargs) kwargs["is_debug"] = 1 self._log(level, _format, *args, **kwargs) def exception(self): self._log(self.TRACEBACK, traceback.format_exc(), args=[], kwargs={}) ### internal functions def _checkLogLevel(self, level, min_level, max_level): if level < min_level or level > max_level: raise ValueError("Level %d out of range, should be [%d..%d]." % \ (level, min_level, max_level)) def _checkKWargs(self, kwargs): if not kwargs: return for key in kwargs.keys(): if key not in [ "nl", "fmt", "nofmt" ]: raise ValueError("Key '%s' is not allowed as argument for logging." % key) def _checkDomain(self, domain): if not domain or domain == "": raise ValueError("Domain '%s' is not valid." % domain) def _getLevels(self, level, is_debug=0): """ Generate log level array. """ if level != self.ALL: if isinstance(level, list) or isinstance(level, tuple): levels = level else: levels = [ level ] for level in levels: if is_debug: self._checkLogLevel(level, min_level=1, max_level=self.DEBUG_MAX) else: self._checkLogLevel(level, min_level=self.FATAL, max_level=self.INFO_MAX) else: if is_debug: levels = [ i for i in range(self.DEBUG1, self.DEBUG_MAX) ] else: levels = [ i for i in range(self.FATAL, self.INFO_MAX) ] return levels def _getTargets(self, target): """ Generate target array. """ if isinstance(target, list) or isinstance(target, tuple): targets = target else: targets = [ target ] for _target in targets: if not issubclass(_target.__class__, LogTarget): raise ValueError("'%s' is no valid logging target." % \ _target.__class__.__name__) return targets def _genDomains(self, is_debug=0): # private method for self._domains array creation, speeds up """ Generate dict with domain by level. """ if is_debug: _domains = self._debug_domains _logging = self._debug_logging _range = ( 1, self.DEBUG_MAX+1 ) else: _domains = self._domains _logging = self._logging _range = ( self.FATAL, self.INFO_MAX+1 ) if len(_domains) > 0: _domains.clear() for level in range(_range[0], _range[1]): if level not in _logging: continue for (domain, dummy, dummy) in _logging[level]: if domain not in _domains: _domains.setdefault(level, [ ]).append(domain) def _setLogging(self, domain, target, level=ALL, fmt=None, is_debug=0): self._checkDomain(domain) levels = self._getLevels(level, is_debug) targets = self._getTargets(target) if is_debug: _logging = self._debug_logging else: _logging = self._logging for level in levels: for target in targets: _logging[level] = [ (domain, target, fmt) ] self._genDomains(is_debug) def _addLogging(self, domain, target, level=ALL, fmt=None, is_debug=0): self._checkDomain(domain) levels = self._getLevels(level, is_debug) targets = self._getTargets(target) if is_debug: _logging = self._debug_logging else: _logging = self._logging for level in levels: for target in targets: _logging.setdefault(level, [ ]).append((domain, target, fmt)) self._genDomains(is_debug) def _delLogging(self, domain, target, level=ALL, fmt=None, is_debug=0): self._checkDomain(domain) levels = self._getLevels(level, is_debug) targets = self._getTargets(target) if is_debug: _logging = self._debug_logging else: _logging = self._logging for _level in levels: for target in targets: if _level not in _logging: continue if (domain, target, fmt) in _logging[_level]: _logging[_level].remove( (domain, target, fmt) ) if len(_logging[_level]) == 0: del _logging[_level] continue if level != self.ALL: raise ValueError("No mathing logging for " \ "level %d, domain %s, target %s and format %s." % \ (_level, domain, target.__class__.__name__, fmt)) self._genDomains(is_debug) def _isLoggingHere(self, level, is_debug=0): _dict = self._genDict(level, is_debug) if not _dict: return False point_domain = _dict["domain"] + "." if is_debug: _logging = self._debug_logging else: _logging = self._logging # do we need to log? for (domain, dummy, dummy) in _logging[level]: if domain == "*" or \ point_domain.startswith(domain) or \ fnmatch.fnmatchcase(_dict["domain"], domain): return True return False def _getClass(self, frame): """ Function to get calling class. Returns class or None. """ # get class by first function argument, if there are any if frame.f_code.co_argcount > 0: selfname = frame.f_code.co_varnames[0] if selfname in frame.f_locals: _self = frame.f_locals[selfname] obj = self._getClass2(_self.__class__, frame.f_code) if obj: return obj module = inspect.getmodule(frame.f_code) code = frame.f_code # function in module? if code.co_name in module.__dict__: if hasattr(module.__dict__[code.co_name], "func_code") and \ module.__dict__[code.co_name].__code__ == code: return None # class in module for (dummy, obj) in module.__dict__.items(): if isinstance(obj, types.ClassType): if hasattr(obj, code.co_name): value = getattr(obj, code.co_name) if isinstance(value, types.FunctionType): if value.__code__ == code: return obj # nothing found return None def _getClass2(self, obj, code): """ Internal function to get calling class. Returns class or None. """ for value in obj.__dict__.values(): if isinstance(value, types.FunctionType): if value.__code__ == code: return obj for base in obj.__bases__: _obj = self._getClass2(base, code) if _obj: return _obj return None # internal log class def _log(self, level, _format, *args, **kwargs): is_debug = 0 if "is_debug" in kwargs: is_debug = kwargs["is_debug"] nl = 1 if "nl" in kwargs: nl = kwargs["nl"] nofmt = 0 if "nofmt" in kwargs: nofmt = kwargs["nofmt"] _dict = self._genDict(level, is_debug) if not _dict: return if len(args) > 1: _dict['message'] = _format % args elif len(args) == 1: # needed for _format % _dict _dict['message'] = _format % args[0] else: _dict['message'] = _format point_domain = _dict["domain"] + "." if is_debug: _logging = self._debug_logging else: _logging = self._logging used_targets = [ ] # log to target(s) for (domain, target, _format) in _logging[level]: if target in used_targets: continue if domain == "*" \ or point_domain.startswith(domain+".") \ or fnmatch.fnmatchcase(_dict["domain"], domain): if not _format: _format = self._format if "fmt" in kwargs: _format = kwargs["fmt"] if nofmt: target.write(_dict["message"], level, self, is_debug) else: target.write(_format % _dict, level, self, is_debug) if nl: # newline target.write("\n", level, self, is_debug) used_targets.append(target) # internal function to generate the dict, needed for logging def _genDict(self, level, is_debug=0): """ Internal function. """ check_domains = [ ] simple_match = False if is_debug: _dict = self._debug_level _domains = self._debug_domains _label = self._debug_label else: _dict = self._level _domains = self._domains _label = self._label # no debug for domain in _dict: if domain == "*": # '*' matches everything: simple match if _dict[domain] >= level: simple_match = True if len(check_domains) > 0: check_domains = [ ] break else: if _dict[domain] >= level: check_domains.append(domain) if not simple_match and len(check_domains) < 1: return None if level not in _domains: return None f = inspect.currentframe() # go outside of logger module as long as there is a lower frame while f and f.f_back and f.f_globals["__name__"] == self.__module__: f = f.f_back if not f: raise ValueError("Frame information not available.") # get module name module_name = f.f_globals["__name__"] # simple module match test for all entries of check_domain point_module = module_name + "." for domain in check_domains: if point_module.startswith(domain): # found domain in module name check_domains = [ ] break # get code co = f.f_code # optimization: bail out early if domain can not match at all _len = len(module_name) for domain in _domains[level]: i = domain.find("*") if i == 0: continue elif i > 0: d = domain[:i] else: d = domain if _len >= len(d): if not module_name.startswith(d): return None else: if not d.startswith(module_name): return None # generate _dict for format output level_str = "" if level in _label: level_str = _label[level] _dict = { 'file': co.co_filename, 'line': f.f_lineno, 'module': module_name, 'class': '', 'function': co.co_name, 'domain': '', 'label' : level_str, 'level' : level, 'date' : time.strftime(self._date_format, time.localtime()) } if _dict["function"] == "?": _dict["function"] = "" # domain match needed? domain_needed = False for domain in _domains[level]: # standard domain, matches everything if domain == "*": continue # domain is needed domain_needed = True break # do we need to get the class object? if self._format.find("%(domain)") >= 0 or \ self._format.find("%(class)") >= 0 or \ domain_needed or \ len(check_domains) > 0: obj = self._getClass(f) if obj: _dict["class"] = obj.__name__ # build domain string _dict["domain"] = "" + _dict["module"] if _dict["class"] != "": _dict["domain"] += "." + _dict["class"] if _dict["function"] != "": _dict["domain"] += "." + _dict["function"] if len(check_domains) < 1: return _dict point_domain = _dict["domain"] + "." for domain in check_domains: if point_domain.startswith(domain) or \ fnmatch.fnmatchcase(_dict["domain"], domain): return _dict return None # --------------------------------------------------------------------------- # Global logging object. log = Logger() # --------------------------------------------------------------------------- """ # Example if __name__ == '__main__': log.setInfoLogLevel(log.INFO2) log.setDebugLogLevel(log.DEBUG5) for i in range(log.INFO1, log.INFO_MAX+1): log.setInfoLogLabel(i, "INFO%d: " % i) for i in range(log.DEBUG1, log.DEBUG_MAX+1): log.setDebugLogLabel(i, "DEBUG%d: " % i) log.setFormat("%(date)s %(module)s:%(line)d %(label)s" "%(message)s") log.setDateFormat("%Y-%m-%d %H:%M:%S") fl = FileLog("/tmp/log", "a") log.addInfoLogging("*", fl) log.delDebugLogging("*", log.stdout) log.setDebugLogging("*", log.stdout, [ log.DEBUG1, log.DEBUG2 ] ) log.addDebugLogging("*", fl) # log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s") # log.addDebugLogging("*", log.syslog, fmt="%(label)s%(message)s") log.debug10("debug10") log.debug9("debug9") log.debug8("debug8") log.debug7("debug7") log.debug6("debug6") log.debug5("debug5") log.debug4("debug4") log.debug3("debug3") log.debug2("debug2", fmt="%(file)s:%(line)d %(message)s") log.debug1("debug1", nofmt=1) log.info5("info5") log.info4("info4") log.info3("info3") log.info2("info2") log.info1("info1") log.warning("warning\n", nl=0) log.error("error ", nl=0) log.error("error", nofmt=1) log.fatal("fatal") log.info(log.INFO1, "nofmt info", nofmt=1) log.info(log.INFO2, "info2 fmt", fmt="%(file)s:%(line)d %(message)s") try: a = b except Exception as e: log.exception() """ # vim:ts=4:sw=4:showmatch:expandtab PKpge[gfw.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "Firewall" ] import os.path import sys import copy import time import traceback from firewall import config from firewall import functions from firewall.core import ipXtables from firewall.core import ebtables from firewall.core import nftables from firewall.core import ipset from firewall.core import modules from firewall.core.fw_icmptype import FirewallIcmpType from firewall.core.fw_service import FirewallService from firewall.core.fw_zone import FirewallZone from firewall.core.fw_direct import FirewallDirect from firewall.core.fw_config import FirewallConfig from firewall.core.fw_policies import FirewallPolicies from firewall.core.fw_ipset import FirewallIPSet from firewall.core.fw_transaction import FirewallTransaction from firewall.core.fw_helper import FirewallHelper from firewall.core.fw_policy import FirewallPolicy from firewall.core.fw_nm import nm_get_bus_name, nm_get_interfaces_in_zone from firewall.core.logger import log from firewall.core.io.firewalld_conf import firewalld_conf from firewall.core.io.direct import Direct from firewall.core.io.service import service_reader from firewall.core.io.icmptype import icmptype_reader from firewall.core.io.zone import zone_reader, Zone from firewall.core.io.ipset import ipset_reader from firewall.core.ipset import IPSET_TYPES from firewall.core.io.helper import helper_reader from firewall.core.io.policy import policy_reader from firewall import errors from firewall.errors import FirewallError ############################################################################ # # class Firewall # ############################################################################ class Firewall(object): def __init__(self, offline=False): self._firewalld_conf = firewalld_conf(config.FIREWALLD_CONF) self._offline = offline if self._offline: self.ip4tables_enabled = False self.ip6tables_enabled = False self.ebtables_enabled = False self.ipset_enabled = False self.ipset_supported_types = IPSET_TYPES self.nftables_enabled = False else: self.ip4tables_backend = ipXtables.ip4tables(self) self.ip4tables_enabled = True self.ipv4_supported_icmp_types = [ ] self.ip6tables_backend = ipXtables.ip6tables(self) self.ip6tables_enabled = True self.ipv6_supported_icmp_types = [ ] self.ebtables_backend = ebtables.ebtables() self.ebtables_enabled = True self.ipset_backend = ipset.ipset() self.ipset_enabled = True self.ipset_supported_types = [ ] self.nftables_backend = nftables.nftables(self) self.nftables_enabled = True self.modules_backend = modules.modules() self.icmptype = FirewallIcmpType(self) self.service = FirewallService(self) self.zone = FirewallZone(self) self.direct = FirewallDirect(self) self.config = FirewallConfig(self) self.policies = FirewallPolicies() self.ipset = FirewallIPSet(self) self.helper = FirewallHelper(self) self.policy = FirewallPolicy(self) self.__init_vars() def __repr__(self): return '%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)' % \ (self.__class__, self.ip4tables_enabled, self.ip6tables_enabled, self.ebtables_enabled, self._state, self._panic, self._default_zone, self._module_refcount, self._marks, self.cleanup_on_exit, self.cleanup_modules_on_exit, self.ipv6_rpfilter_enabled, self.ipset_enabled, self._individual_calls, self._log_denied) def __init_vars(self): self._state = "INIT" self._panic = False self._default_zone = "" self._module_refcount = { } self._marks = [ ] # fallback settings will be overloaded by firewalld.conf self.cleanup_on_exit = config.FALLBACK_CLEANUP_ON_EXIT self.cleanup_modules_on_exit = config.FALLBACK_CLEANUP_MODULES_ON_EXIT self.ipv6_rpfilter_enabled = config.FALLBACK_IPV6_RPFILTER self._individual_calls = config.FALLBACK_INDIVIDUAL_CALLS self._log_denied = config.FALLBACK_LOG_DENIED self._firewall_backend = config.FALLBACK_FIREWALL_BACKEND self._flush_all_on_reload = config.FALLBACK_FLUSH_ALL_ON_RELOAD self._rfc3964_ipv4 = config.FALLBACK_RFC3964_IPV4 self._allow_zone_drifting = config.FALLBACK_ALLOW_ZONE_DRIFTING def _check_tables(self): # check if iptables, ip6tables and ebtables are usable, else disable if self.ip4tables_enabled and \ "filter" not in self.ip4tables_backend.get_available_tables(): log.info1("iptables is not usable.") self.ip4tables_enabled = False if self.ip6tables_enabled and \ "filter" not in self.ip6tables_backend.get_available_tables(): log.info1("ip6tables is not usable.") self.ip6tables_enabled = False if self.ebtables_enabled and \ "filter" not in self.ebtables_backend.get_available_tables(): log.info1("ebtables is not usable.") self.ebtables_enabled = False # is there at least support for ipv4 or ipv6 if not self.ip4tables_enabled and not self.ip6tables_enabled \ and not self.nftables_enabled: log.fatal("No IPv4 and IPv6 firewall.") sys.exit(1) def _start_check(self): try: self.ipset_backend.set_list() except ValueError: log.warning("ipset not usable, disabling ipset usage in firewall.") # ipset is not usable, no supported types self.ipset_enabled = False self.ipset_supported_types = [ ] else: # ipset is usable, get all supported types self.ipset_supported_types = self.ipset_backend.set_supported_types() self.ip4tables_backend.fill_exists() if not self.ip4tables_backend.restore_command_exists: if self.ip4tables_backend.command_exists: log.warning("iptables-restore is missing, using " "individual calls for IPv4 firewall.") else: log.warning("iptables-restore and iptables are missing, " "disabling IPv4 firewall.") self.ip4tables_enabled = False if self.nftables_enabled: self.ipv4_supported_icmp_types = self.nftables_backend.supported_icmp_types("ipv4") else: if self.ip4tables_enabled: self.ipv4_supported_icmp_types = self.ip4tables_backend.supported_icmp_types() else: self.ipv4_supported_icmp_types = [ ] self.ip6tables_backend.fill_exists() if not self.ip6tables_backend.restore_command_exists: if self.ip6tables_backend.command_exists: log.warning("ip6tables-restore is missing, using " "individual calls for IPv6 firewall.") else: log.warning("ip6tables-restore and ip6tables are missing, " "disabling IPv6 firewall.") self.ip6tables_enabled = False if self.nftables_enabled: self.ipv6_supported_icmp_types = self.nftables_backend.supported_icmp_types("ipv6") else: if self.ip6tables_enabled: self.ipv6_supported_icmp_types = self.ip6tables_backend.supported_icmp_types() else: self.ipv6_supported_icmp_types = [ ] self.ebtables_backend.fill_exists() if not self.ebtables_backend.restore_command_exists: if self.ebtables_backend.command_exists: log.warning("ebtables-restore is missing, using " "individual calls for bridge firewall.") else: log.warning("ebtables-restore and ebtables are missing, " "disabling bridge firewall.") self.ebtables_enabled = False if self.ebtables_enabled and not self._individual_calls and \ not self.ebtables_backend.restore_noflush_option: log.debug1("ebtables-restore is not supporting the --noflush " "option, will therefore not be used") def _start(self, reload=False, complete_reload=False): # initialize firewall default_zone = config.FALLBACK_ZONE # load firewalld config log.debug1("Loading firewalld config file '%s'", config.FIREWALLD_CONF) try: self._firewalld_conf.read() except Exception as msg: log.warning(msg) log.warning("Using fallback firewalld configuration settings.") else: if self._firewalld_conf.get("DefaultZone"): default_zone = self._firewalld_conf.get("DefaultZone") if self._firewalld_conf.get("CleanupOnExit"): value = self._firewalld_conf.get("CleanupOnExit") if value is not None and value.lower() in [ "no", "false" ]: self.cleanup_on_exit = False log.debug1("CleanupOnExit is set to '%s'", self.cleanup_on_exit) if self._firewalld_conf.get("CleanupModulesOnExit"): value = self._firewalld_conf.get("CleanupModulesOnExit") if value is not None and value.lower() in [ "yes", "true" ]: self.cleanup_modules_on_exit = True if value is not None and value.lower() in [ "no", "false" ]: self.cleanup_modules_on_exit = False log.debug1("CleanupModulesOnExit is set to '%s'", self.cleanup_modules_on_exit) if self._firewalld_conf.get("Lockdown"): value = self._firewalld_conf.get("Lockdown") if value is not None and value.lower() in [ "yes", "true" ]: log.debug1("Lockdown is enabled") try: self.policies.enable_lockdown() except FirewallError: # already enabled, this is probably reload pass if self._firewalld_conf.get("IPv6_rpfilter"): value = self._firewalld_conf.get("IPv6_rpfilter") if value is not None: if value.lower() in [ "no", "false" ]: self.ipv6_rpfilter_enabled = False if value.lower() in [ "yes", "true" ]: self.ipv6_rpfilter_enabled = True if self.ipv6_rpfilter_enabled: log.debug1("IPv6 rpfilter is enabled") else: log.debug1("IPV6 rpfilter is disabled") if self._firewalld_conf.get("IndividualCalls"): value = self._firewalld_conf.get("IndividualCalls") if value is not None and value.lower() in [ "yes", "true" ]: log.debug1("IndividualCalls is enabled") self._individual_calls = True if self._firewalld_conf.get("LogDenied"): value = self._firewalld_conf.get("LogDenied") if value is None or value.lower() == "no": self._log_denied = "off" else: self._log_denied = value.lower() log.debug1("LogDenied is set to '%s'", self._log_denied) if self._firewalld_conf.get("FirewallBackend"): self._firewall_backend = self._firewalld_conf.get("FirewallBackend") log.debug1("FirewallBackend is set to '%s'", self._firewall_backend) if self._firewalld_conf.get("FlushAllOnReload"): value = self._firewalld_conf.get("FlushAllOnReload") if value.lower() in [ "no", "false" ]: self._flush_all_on_reload = False else: self._flush_all_on_reload = True log.debug1("FlushAllOnReload is set to '%s'", self._flush_all_on_reload) if self._firewalld_conf.get("RFC3964_IPv4"): value = self._firewalld_conf.get("RFC3964_IPv4") if value.lower() in [ "no", "false" ]: self._rfc3964_ipv4 = False else: self._rfc3964_ipv4 = True log.debug1("RFC3964_IPv4 is set to '%s'", self._rfc3964_ipv4) if self._firewalld_conf.get("AllowZoneDrifting"): value = self._firewalld_conf.get("AllowZoneDrifting") if value.lower() in [ "no", "false" ]: self._allow_zone_drifting = False else: self._allow_zone_drifting = True if not self._offline: log.warning("AllowZoneDrifting is enabled. This is considered " "an insecure configuration option. It will be " "removed in a future release. Please consider " "disabling it now.") log.debug1("AllowZoneDrifting is set to '%s'", self._allow_zone_drifting) self.config.set_firewalld_conf(copy.deepcopy(self._firewalld_conf)) self._select_firewall_backend(self._firewall_backend) if not self._offline: self._start_check() # load lockdown whitelist log.debug1("Loading lockdown whitelist") try: self.policies.lockdown_whitelist.read() except Exception as msg: if self.policies.query_lockdown(): log.error("Failed to load lockdown whitelist '%s': %s", self.policies.lockdown_whitelist.filename, msg) else: log.debug1("Failed to load lockdown whitelist '%s': %s", self.policies.lockdown_whitelist.filename, msg) # copy policies to config interface self.config.set_policies(copy.deepcopy(self.policies)) # load ipset files self._loader(config.FIREWALLD_IPSETS, "ipset") self._loader(config.ETC_FIREWALLD_IPSETS, "ipset") # load icmptype files self._loader(config.FIREWALLD_ICMPTYPES, "icmptype") self._loader(config.ETC_FIREWALLD_ICMPTYPES, "icmptype") if len(self.icmptype.get_icmptypes()) == 0: log.error("No icmptypes found.") # load helper files self._loader(config.FIREWALLD_HELPERS, "helper") self._loader(config.ETC_FIREWALLD_HELPERS, "helper") # load service files self._loader(config.FIREWALLD_SERVICES, "service") self._loader(config.ETC_FIREWALLD_SERVICES, "service") if len(self.service.get_services()) == 0: log.error("No services found.") # load zone files self._loader(config.FIREWALLD_ZONES, "zone") self._loader(config.ETC_FIREWALLD_ZONES, "zone") if len(self.zone.get_zones()) == 0: log.fatal("No zones found.") sys.exit(1) # load policy files self._loader(config.FIREWALLD_POLICIES, "policy") self._loader(config.ETC_FIREWALLD_POLICIES, "policy") # check minimum required zones error = False for z in [ "block", "drop", "trusted" ]: if z not in self.zone.get_zones(): log.fatal("Zone '%s' is not available.", z) error = True if error: sys.exit(1) # check if default_zone is a valid zone if default_zone not in self.zone.get_zones(): if "public" in self.zone.get_zones(): zone = "public" elif "external" in self.zone.get_zones(): zone = "external" else: zone = "block" # block is a base zone, therefore it has to exist log.error("Default zone '%s' is not valid. Using '%s'.", default_zone, zone) default_zone = zone else: log.debug1("Using default zone '%s'", default_zone) # load direct rules obj = Direct(config.FIREWALLD_DIRECT) if os.path.exists(config.FIREWALLD_DIRECT): log.debug1("Loading direct rules file '%s'" % \ config.FIREWALLD_DIRECT) try: obj.read() except Exception as msg: log.error("Failed to load direct rules file '%s': %s", config.FIREWALLD_DIRECT, msg) self.direct.set_permanent_config(obj) self.config.set_direct(copy.deepcopy(obj)) self._default_zone = self.check_zone(default_zone) if self._offline: return # check if needed tables are there self._check_tables() if log.getDebugLogLevel() > 0: # get time before flushing and applying tm1 = time.time() # Start transaction transaction = FirewallTransaction(self) # flush rules if not reload: self.flush(use_transaction=transaction) # If modules need to be unloaded in complete reload or if there are # ipsets to get applied, limit the transaction to flush. # # Future optimization for the ipset case in reload: The transaction # only needs to be split here if there are conflicting ipset types in # exsting ipsets and the configuration in firewalld. if (reload and complete_reload) or \ (self.ipset_enabled and self.ipset.has_ipsets()): transaction.execute(True) transaction.clear() # complete reload: unload modules also if reload and complete_reload: log.debug1("Unloading firewall modules") self.modules_backend.unload_firewall_modules() self.apply_default_tables(use_transaction=transaction) transaction.execute(True) transaction.clear() # apply settings for loaded ipsets while reloading here if self.ipset_enabled and self.ipset.has_ipsets(): log.debug1("Applying ipsets") self.ipset.apply_ipsets() # Start or continue with transaction # apply default rules log.debug1("Applying default rule set") self.apply_default_rules(use_transaction=transaction) # apply settings for loaded zones log.debug1("Applying used zones") self.zone.apply_zones(use_transaction=transaction) self.zone.change_default_zone(None, self._default_zone, use_transaction=transaction) # apply policies log.debug1("Applying used policies") self.policy.apply_policies(use_transaction=transaction) # Execute transaction transaction.execute(True) # Start new transaction for direct rules transaction.clear() # apply direct chains, rules and passthrough rules if self.direct.has_configuration(): log.debug1("Applying direct chains rules and passthrough rules") self.direct.apply_direct(transaction) # since direct rules are easy to make syntax errors lets highlight # the cause if the transaction fails. try: transaction.execute(True) transaction.clear() except FirewallError as e: raise FirewallError(e.code, "Direct: %s" % (e.msg if e.msg else "")) except Exception: raise del transaction if log.getDebugLogLevel() > 1: # get time after flushing and applying tm2 = time.time() log.debug2("Flushing and applying took %f seconds" % (tm2 - tm1)) def start(self): try: self._start() except Exception: self._state = "FAILED" self.set_policy("ACCEPT") raise else: self._state = "RUNNING" self.set_policy("ACCEPT") def _loader(self, path, reader_type, combine=False): # combine: several zone files are getting combined into one obj if not os.path.isdir(path): return if combine: if path.startswith(config.ETC_FIREWALLD) and reader_type == "zone": combined_zone = Zone() combined_zone.name = os.path.basename(path) combined_zone.check_name(combined_zone.name) combined_zone.path = path combined_zone.default = False else: combine = False for filename in sorted(os.listdir(path)): if not filename.endswith(".xml"): if path.startswith(config.ETC_FIREWALLD) and \ reader_type == "zone" and \ os.path.isdir("%s/%s" % (path, filename)): self._loader("%s/%s" % (path, filename), reader_type, combine=True) continue name = "%s/%s" % (path, filename) log.debug1("Loading %s file '%s'", reader_type, name) try: if reader_type == "icmptype": obj = icmptype_reader(filename, path) if obj.name in self.icmptype.get_icmptypes(): orig_obj = self.icmptype.get_icmptype(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.icmptype.remove_icmptype(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True try: self.icmptype.add_icmptype(obj) except FirewallError as error: log.info1("%s: %s, ignoring for run-time." % \ (obj.name, str(error))) # add a deep copy to the configuration interface self.config.add_icmptype(copy.deepcopy(obj)) elif reader_type == "service": obj = service_reader(filename, path) if obj.name in self.service.get_services(): orig_obj = self.service.get_service(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.service.remove_service(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True self.service.add_service(obj) # add a deep copy to the configuration interface self.config.add_service(copy.deepcopy(obj)) elif reader_type == "zone": obj = zone_reader(filename, path, no_check_name=combine) if combine: # Change name for permanent configuration obj.name = "%s/%s" % ( os.path.basename(path), os.path.basename(filename)[0:-4]) obj.check_name(obj.name) # Copy object before combine config_obj = copy.deepcopy(obj) if obj.name in self.zone.get_zones(): orig_obj = self.zone.get_zone(obj.name) self.zone.remove_zone(orig_obj.name) if orig_obj.combined: log.debug1(" Combining %s '%s' ('%s/%s')", reader_type, obj.name, path, filename) obj.combine(orig_obj) else: log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True config_obj.default = True self.config.add_zone(config_obj) if combine: log.debug1(" Combining %s '%s' ('%s/%s')", reader_type, combined_zone.name, path, filename) combined_zone.combine(obj) else: self.zone.add_zone(obj) elif reader_type == "ipset": obj = ipset_reader(filename, path) if obj.name in self.ipset.get_ipsets(): orig_obj = self.ipset.get_ipset(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.ipset.remove_ipset(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True try: self.ipset.add_ipset(obj) except FirewallError as error: log.warning("%s: %s, ignoring for run-time." % \ (obj.name, str(error))) # add a deep copy to the configuration interface self.config.add_ipset(copy.deepcopy(obj)) elif reader_type == "helper": obj = helper_reader(filename, path) if obj.name in self.helper.get_helpers(): orig_obj = self.helper.get_helper(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.helper.remove_helper(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True self.helper.add_helper(obj) # add a deep copy to the configuration interface self.config.add_helper(copy.deepcopy(obj)) elif reader_type == "policy": obj = policy_reader(filename, path) if obj.name in self.policy.get_policies(): orig_obj = self.policy.get_policy(obj.name) log.debug1(" Overloads %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) self.policy.remove_policy(orig_obj.name) elif obj.path.startswith(config.ETC_FIREWALLD): obj.default = True self.policy.add_policy(obj) # add a deep copy to the configuration interface self.config.add_policy_object(copy.deepcopy(obj)) else: log.fatal("Unknown reader type %s", reader_type) except FirewallError as msg: log.error("Failed to load %s file '%s': %s", reader_type, name, msg) except Exception: log.error("Failed to load %s file '%s':", reader_type, name) log.exception() if combine and combined_zone.combined: if combined_zone.name in self.zone.get_zones(): orig_obj = self.zone.get_zone(combined_zone.name) log.debug1(" Overloading and deactivating %s '%s' ('%s/%s')", reader_type, orig_obj.name, orig_obj.path, orig_obj.filename) try: self.zone.remove_zone(combined_zone.name) except Exception: pass self.config.forget_zone(combined_zone.name) self.zone.add_zone(combined_zone) def cleanup(self): self.icmptype.cleanup() self.service.cleanup() self.zone.cleanup() self.ipset.cleanup() self.helper.cleanup() self.config.cleanup() self.direct.cleanup() self.policies.cleanup() self.policy.cleanup() self._firewalld_conf.cleanup() self.__init_vars() def stop(self): if not self._offline: if self.cleanup_on_exit: self.flush() self.ipset.flush() self.set_policy("ACCEPT") if self.cleanup_modules_on_exit: log.debug1('Unloading firewall kernel modules') self.modules_backend.unload_firewall_modules() self.cleanup() # handle modules def handle_modules(self, _modules, enable): num_failed = 0 error_msgs = "" for i,module in enumerate(_modules): if enable: (status, msg) = self.modules_backend.load_module(module) else: if self._module_refcount[module] > 1: status = 0 # module referenced more then one, do not unload else: (status, msg) = self.modules_backend.unload_module(module) if status != 0: num_failed += 1 error_msgs += msg continue if enable: self._module_refcount.setdefault(module, 0) self._module_refcount[module] += 1 else: if module in self._module_refcount: self._module_refcount[module] -= 1 if self._module_refcount[module] == 0: del self._module_refcount[module] return (num_failed, error_msgs) def _select_firewall_backend(self, backend): if backend != "nftables": self.nftables_enabled = False # even if using nftables, the other backends are enabled for use with # the direct interface. nftables is used for the firewalld primitives. def get_backend_by_name(self, name): for backend in self.all_backends(): if backend.name == name: return backend raise FirewallError(errors.UNKNOWN_ERROR, "'%s' backend does not exist" % name) def get_backend_by_ipv(self, ipv): if self.nftables_enabled: return self.nftables_backend if ipv == "ipv4" and self.ip4tables_enabled: return self.ip4tables_backend elif ipv == "ipv6" and self.ip6tables_enabled: return self.ip6tables_backend elif ipv == "eb" and self.ebtables_enabled: return self.ebtables_backend raise FirewallError(errors.INVALID_IPV, "'%s' is not a valid backend or is unavailable" % ipv) def get_direct_backend_by_ipv(self, ipv): if ipv == "ipv4" and self.ip4tables_enabled: return self.ip4tables_backend elif ipv == "ipv6" and self.ip6tables_enabled: return self.ip6tables_backend elif ipv == "eb" and self.ebtables_enabled: return self.ebtables_backend raise FirewallError(errors.INVALID_IPV, "'%s' is not a valid backend or is unavailable" % ipv) def is_backend_enabled(self, name): if name == "ip4tables": return self.ip4tables_enabled elif name == "ip6tables": return self.ip6tables_enabled elif name == "ebtables": return self.ebtables_enabled elif name == "nftables": return self.nftables_enabled return False def is_ipv_enabled(self, ipv): if self.nftables_enabled: return True if ipv == "ipv4": return self.ip4tables_enabled elif ipv == "ipv6": return self.ip6tables_enabled elif ipv == "eb": return self.ebtables_enabled return False def enabled_backends(self): backends = [] if self.nftables_enabled: backends.append(self.nftables_backend) else: if self.ip4tables_enabled: backends.append(self.ip4tables_backend) if self.ip6tables_enabled: backends.append(self.ip6tables_backend) if self.ebtables_enabled: backends.append(self.ebtables_backend) return backends def all_backends(self): backends = [] if self.ip4tables_enabled: backends.append(self.ip4tables_backend) if self.ip6tables_enabled: backends.append(self.ip6tables_backend) if self.ebtables_enabled: backends.append(self.ebtables_backend) if self.nftables_enabled: backends.append(self.nftables_backend) return backends def apply_default_tables(self, use_transaction=None): if use_transaction is None: transaction = FirewallTransaction(self) else: transaction = use_transaction for backend in self.enabled_backends(): transaction.add_rules(backend, backend.build_default_tables()) if use_transaction is None: transaction.execute(True) def apply_default_rules(self, use_transaction=None): if use_transaction is None: transaction = FirewallTransaction(self) else: transaction = use_transaction for backend in self.enabled_backends(): rules = backend.build_default_rules(self._log_denied) transaction.add_rules(backend, rules) if self.is_ipv_enabled("ipv6"): ipv6_backend = self.get_backend_by_ipv("ipv6") if "raw" in ipv6_backend.get_available_tables(): if self.ipv6_rpfilter_enabled: rules = ipv6_backend.build_rpfilter_rules(self._log_denied) transaction.add_rules(ipv6_backend, rules) if self.is_ipv_enabled("ipv6") and self._rfc3964_ipv4: rules = ipv6_backend.build_rfc3964_ipv4_rules() transaction.add_rules(ipv6_backend, rules) if use_transaction is None: transaction.execute(True) def may_skip_flush_direct_backends(self): if self.nftables_enabled and not self.direct.has_runtime_configuration(): return True return False def flush_direct_backends(self, use_transaction=None): if use_transaction is None: transaction = FirewallTransaction(self) else: transaction = use_transaction for backend in self.all_backends(): if backend in self.enabled_backends(): continue rules = backend.build_flush_rules() transaction.add_rules(backend, rules) if use_transaction is None: transaction.execute(True) def flush(self, use_transaction=None): if use_transaction is None: transaction = FirewallTransaction(self) else: transaction = use_transaction log.debug1("Flushing rule set") if not self.may_skip_flush_direct_backends(): self.flush_direct_backends(use_transaction=transaction) for backend in self.enabled_backends(): rules = backend.build_flush_rules() transaction.add_rules(backend, rules) if use_transaction is None: transaction.execute(True) def set_policy(self, policy, use_transaction=None): if use_transaction is None: transaction = FirewallTransaction(self) else: transaction = use_transaction log.debug1("Setting policy to '%s'", policy) for backend in self.enabled_backends(): rules = backend.build_set_policy_rules(policy) transaction.add_rules(backend, rules) if use_transaction is None: transaction.execute(True) # rule function used in handle_ functions def rule(self, backend_name, rule): if not rule: return "" backend = self.get_backend_by_name(backend_name) if not backend: raise FirewallError(errors.INVALID_IPV, "'%s' is not a valid backend" % backend_name) if not self.is_backend_enabled(backend_name): return "" return backend.set_rule(rule, self._log_denied) def rules(self, backend_name, rules): _rules = list(filter(None, rules)) backend = self.get_backend_by_name(backend_name) if not backend: raise FirewallError(errors.INVALID_IPV, "'%s' is not a valid backend" % backend_name) if not self.is_backend_enabled(backend_name): return if self._individual_calls or \ not backend.restore_command_exists or \ (backend_name == "ebtables" and not self.ebtables_backend.restore_noflush_option): for i,rule in enumerate(_rules): try: backend.set_rule(rule, self._log_denied) except Exception as msg: log.debug1(traceback.format_exc()) log.error(msg) for rule in reversed(_rules[:i]): try: backend.set_rule(backend.reverse_rule(rule), self._log_denied) except Exception: # ignore errors here pass raise msg else: backend.set_rules(_rules, self._log_denied) # check functions def check_panic(self): if self._panic: raise FirewallError(errors.PANIC_MODE) def check_policy(self, policy): _policy = policy if _policy not in self.policy.get_policies(): raise FirewallError(errors.INVALID_POLICY, _policy) return _policy def check_zone(self, zone): _zone = zone if not _zone or _zone == "": _zone = self.get_default_zone() if _zone not in self.zone.get_zones(): raise FirewallError(errors.INVALID_ZONE, _zone) return _zone def check_interface(self, interface): if not functions.checkInterface(interface): raise FirewallError(errors.INVALID_INTERFACE, interface) def check_service(self, service): self.service.check_service(service) def check_port(self, port): if not functions.check_port(port): raise FirewallError(errors.INVALID_PORT, port) def check_tcpudp(self, protocol): if not protocol: raise FirewallError(errors.MISSING_PROTOCOL) if protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, "'%s' not in {'tcp'|'udp'|'sctp'|'dccp'}" % \ protocol) def check_ip(self, ip): if not functions.checkIP(ip): raise FirewallError(errors.INVALID_ADDR, ip) def check_address(self, ipv, source): if ipv == "ipv4": if not functions.checkIPnMask(source): raise FirewallError(errors.INVALID_ADDR, source) elif ipv == "ipv6": if not functions.checkIP6nMask(source): raise FirewallError(errors.INVALID_ADDR, source) else: raise FirewallError(errors.INVALID_IPV, "'%s' not in {'ipv4'|'ipv6'}") def check_icmptype(self, icmp): self.icmptype.check_icmptype(icmp) def check_timeout(self, timeout): if not isinstance(timeout, int): raise TypeError("%s is %s, expected int" % (timeout, type(timeout))) if int(timeout) < 0: raise FirewallError(errors.INVALID_VALUE, "timeout '%d' is not positive number" % timeout) # RELOAD def reload(self, stop=False): _panic = self._panic # must stash this. The value may change after _start() flush_all = self._flush_all_on_reload if not flush_all: # save zone interfaces _zone_interfaces = { } for zone in self.zone.get_zones(): _zone_interfaces[zone] = self.zone.get_settings(zone)["interfaces"] # save direct config _direct_config = self.direct.get_runtime_config() _old_dz = self.get_default_zone() _ipset_objs = [] for _name in self.ipset.get_ipsets(): _ipset_objs.append(self.ipset.get_ipset(_name)) if not _panic: self.set_policy("DROP") self.flush() self.cleanup() start_exception = None try: self._start(reload=True, complete_reload=stop) except Exception as e: # save the exception for later, but continue restoring interfaces, # etc. We'll re-raise it at the end. start_exception = e # destroy ipsets no longer in the permanent configuration if flush_all: for obj in _ipset_objs: if not self.ipset.query_ipset(obj.name): for backend in self.ipset.backends(): # nftables sets are part of the normal firewall ruleset. if backend.name == "nftables": continue backend.set_destroy(obj.name) if not flush_all: # handle interfaces in the default zone and move them to the new # default zone if it changed _new_dz = self.get_default_zone() if _new_dz != _old_dz: # if_new_dz has been introduced with the reload, we need to add it # https://github.com/firewalld/firewalld/issues/53 if _new_dz not in _zone_interfaces: _zone_interfaces[_new_dz] = { } # default zone changed. Move interfaces from old default zone to # the new one. for iface, settings in list(_zone_interfaces[_old_dz].items()): if settings["__default__"]: # move only those that were added to default zone # (not those that were added to specific zone same as # default) _zone_interfaces[_new_dz][iface] = \ _zone_interfaces[_old_dz][iface] del _zone_interfaces[_old_dz][iface] # add interfaces to zones again for zone in self.zone.get_zones(): if zone in _zone_interfaces: for interface_id in _zone_interfaces[zone]: self.zone.change_zone_of_interface(zone, interface_id, _zone_interfaces[zone][interface_id]["sender"]) del _zone_interfaces[zone] else: log.info1("New zone '%s'.", zone) if len(_zone_interfaces) > 0: for zone in list(_zone_interfaces.keys()): log.info1("Lost zone '%s', zone interfaces dropped.", zone) del _zone_interfaces[zone] del _zone_interfaces # restore runtime-only ipsets for obj in _ipset_objs: if self.ipset.query_ipset(obj.name): for entry in obj.entries: try: self.ipset.add_entry(obj.name, entry) except FirewallError as msg: if msg.code != errors.ALREADY_ENABLED: raise msg else: self.ipset.add_ipset(obj) self.ipset.apply_ipset(obj.name) # restore direct config self.direct.set_config(_direct_config) # Restore permanent interfaces from NetworkManager nm_bus_name = nm_get_bus_name() if nm_bus_name: for zone in self.zone.get_zones() + [""]: for interface in nm_get_interfaces_in_zone(zone): self.zone.change_zone_of_interface(zone, interface, sender=nm_bus_name) self._panic = _panic if not self._panic: self.set_policy("ACCEPT") if start_exception: self._state = "FAILED" raise start_exception else: self._state = "RUNNING" # STATE def get_state(self): return self._state # PANIC MODE def enable_panic_mode(self): if self._panic: raise FirewallError(errors.ALREADY_ENABLED, "panic mode already enabled") try: self.set_policy("PANIC") except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) self._panic = True def disable_panic_mode(self): if not self._panic: raise FirewallError(errors.NOT_ENABLED, "panic mode is not enabled") try: self.set_policy("ACCEPT") except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) self._panic = False def query_panic_mode(self): return self._panic # LOG DENIED def get_log_denied(self): return self._log_denied def set_log_denied(self, value): if value not in config.LOG_DENIED_VALUES: raise FirewallError(errors.INVALID_VALUE, "'%s', choose from '%s'" % \ (value, "','".join(config.LOG_DENIED_VALUES))) if value != self.get_log_denied(): self._log_denied = value self._firewalld_conf.set("LogDenied", value) self._firewalld_conf.write() else: raise FirewallError(errors.ALREADY_SET, value) # DEFAULT ZONE def get_default_zone(self): return self._default_zone def set_default_zone(self, zone): _zone = self.check_zone(zone) if _zone != self._default_zone: _old_dz = self._default_zone self._default_zone = _zone self._firewalld_conf.set("DefaultZone", _zone) self._firewalld_conf.write() # remove old default zone from ZONES and add new default zone self.zone.change_default_zone(_old_dz, _zone) # Move interfaces from old default zone to the new one. _old_dz_settings = self.zone.get_settings(_old_dz) for iface, settings in list(_old_dz_settings["interfaces"].items()): if settings["__default__"]: # move only those that were added to default zone # (not those that were added to specific zone same as default) self.zone.change_zone_of_interface("", iface) else: raise FirewallError(errors.ZONE_ALREADY_SET, _zone) def combine_runtime_with_permanent_settings(self, permanent, runtime): combined = permanent.copy() for key,value in runtime.items(): # omit empty entries if value or isinstance(value, bool): combined[key] = value # make sure to remove values that were in permanent, but no # longer in runtime. elif key in combined: del combined[key] return combined def get_added_and_removed_settings(self, old_settings, new_settings): add_settings = {} remove_settings = {} for key in (set(old_settings.keys()) | set(new_settings.keys())): if key in new_settings: if isinstance(new_settings[key], list): old = set(old_settings[key] if key in old_settings else []) add_settings[key] = list(set(new_settings[key]) - old) remove_settings[key] = list((old ^ set(new_settings[key])) & old) # check for bool or int because dbus.Boolean is a subclass of # int (because bool can't be subclassed). elif isinstance(new_settings[key], bool) or isinstance(new_settings[key], int): if not old_settings[key] and new_settings[key]: add_settings[key] = True elif old_settings[key] and not new_settings[key]: remove_settings[key] = False else: raise FirewallError(errors.INVALID_SETTING, "Unhandled setting type {} key {}".format(type(new_settings[key]), key)) return (add_settings, remove_settings) PKpge[َ:  fw_ifcfg.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """Functions to search for and change ifcfg files""" __all__ = [ "search_ifcfg_of_interface", "ifcfg_set_zone_of_interface" ] import os import os.path from firewall import config from firewall.core.logger import log from firewall.core.io.ifcfg import ifcfg def search_ifcfg_of_interface(interface): """search ifcfg file for the interface in config.IFCFGDIR""" # Return quickly if config.IFCFGDIR does not exist if not os.path.exists(config.IFCFGDIR): return None for filename in sorted(os.listdir(config.IFCFGDIR)): if not filename.startswith("ifcfg-"): continue for ignored in [ ".bak", ".orig", ".rpmnew", ".rpmorig", ".rpmsave", "-range" ]: if filename.endswith(ignored): continue if "." in filename: continue ifcfg_file = ifcfg("%s/%s" % (config.IFCFGDIR, filename)) ifcfg_file.read() if ifcfg_file.get("DEVICE") == interface: return ifcfg_file # Wasn't found above, so assume filename matches the device we want filename = "%s/ifcfg-%s" % (config.IFCFGDIR, interface) if os.path.exists(filename): ifcfg_file = ifcfg(filename) ifcfg_file.read() return ifcfg_file return None def ifcfg_set_zone_of_interface(zone, interface): """Set zone (ZONE=) in the ifcfg file that uses the interface (DEVICE=)""" if zone is None: zone = "" ifcfg_file = search_ifcfg_of_interface(interface) if ifcfg_file is not None and ifcfg_file.get("ZONE") != zone and not \ (ifcfg_file.get("ZONE") is None and zone == ""): log.debug1("Setting ZONE=%s in '%s'" % (zone, ifcfg_file.filename)) ifcfg_file.set("ZONE", zone) ifcfg_file.write() PKpge[  modules.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """modules backend""" __all__ = [ "modules" ] from firewall.core.prog import runProg from firewall.core.logger import log from firewall.config import COMMANDS class modules(object): def __init__(self): self._load_command = COMMANDS["modprobe"] # Use rmmod instead of modprobe -r (RHBZ#1031102) self._unload_command = COMMANDS["rmmod"] def __repr__(self): return '%s' % (self.__class__) def loaded_modules(self): """ get all loaded kernel modules and their dependencies """ mods = [ ] deps = { } try: with open("/proc/modules", "r") as f: for line in f: if not line: break line = line.strip() splits = line.split() mods.append(splits[0]) if splits[3] != "-": deps[splits[0]] = splits[3].split(",")[:-1] else: deps[splits[0]] = [ ] except FileNotFoundError: pass return mods, deps # [loaded modules], {module:[dependants]} def load_module(self, module): log.debug2("%s: %s %s", self.__class__, self._load_command, module) return runProg(self._load_command, [ module ]) def unload_module(self, module): log.debug2("%s: %s %s", self.__class__, self._unload_command, module) return runProg(self._unload_command, [ module ]) def get_deps(self, module, deps, ret): """ get all dependants of a module """ if module not in deps: return for mod in deps[module]: self.get_deps(mod, deps, ret) if mod not in ret: ret.append(mod) if module not in ret: ret.append(module) def get_firewall_modules(self): """ get all loaded firewall-related modules """ mods = [ ] (mods2, deps) = self.loaded_modules() self.get_deps("nf_conntrack", deps, mods) # these modules don't have dependants listed in /proc/modules for bad_bad_module in ["nf_conntrack_ipv4", "nf_conntrack_ipv6"]: if bad_bad_module in mods: # move them to end of list, so we'll remove them later mods.remove(bad_bad_module) mods.insert(-1, bad_bad_module) for mod in mods2: if mod in [ "ip_tables", "ip6_tables", "ebtables" ] or \ mod.startswith("iptable_") or mod.startswith("ip6table_") or \ mod.startswith("nf_") or mod.startswith("xt_") or \ mod.startswith("ipt_") or mod.startswith("ip6t_") : self.get_deps(mod, deps, mods) return mods def unload_firewall_modules(self): """ unload all firewall-related modules """ for module in self.get_firewall_modules(): (status, ret) = self.unload_module(module) if status != 0: log.debug1("Failed to unload module '%s': %s" %(module, ret)) PKpge[ Pq2q2ipset.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2015-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """The ipset command wrapper""" __all__ = [ "ipset", "check_ipset_name", "remove_default_create_options" ] import os.path import ipaddress from firewall import errors from firewall.errors import FirewallError from firewall.core.prog import runProg from firewall.core.logger import log from firewall.functions import tempFile, readfile from firewall.config import COMMANDS IPSET_MAXNAMELEN = 32 IPSET_TYPES = [ # bitmap and set types are currently not supported # "bitmap:ip", # "bitmap:ip,mac", # "bitmap:port", # "list:set", "hash:ip", "hash:ip,port", "hash:ip,port,ip", "hash:ip,port,net", "hash:ip,mark", "hash:net", "hash:net,net", "hash:net,port", "hash:net,port,net", "hash:net,iface", "hash:mac", ] IPSET_CREATE_OPTIONS = { "family": "inet|inet6", "hashsize": "value", "maxelem": "value", "timeout": "value in secs", #"counters": None, #"comment": None, } IPSET_DEFAULT_CREATE_OPTIONS = { "family": "inet", "hashsize": "1024", "maxelem": "65536", } class ipset(object): """ipset command wrapper class""" def __init__(self): self._command = COMMANDS["ipset"] self.name = "ipset" def __run(self, args): """Call ipset with args""" # convert to string list _args = ["%s" % item for item in args] log.debug2("%s: %s %s", self.__class__, self._command, " ".join(_args)) (status, ret) = runProg(self._command, _args) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._command, " ".join(_args), ret)) return ret def check_name(self, name): """Check ipset name""" if len(name) > IPSET_MAXNAMELEN: raise FirewallError(errors.INVALID_NAME, "ipset name '%s' is not valid" % name) def set_supported_types(self): """Return types that are supported by the ipset command and kernel""" ret = [ ] output = "" try: output = self.__run(["--help"]) except ValueError as ex: log.debug1("ipset error: %s" % ex) lines = output.splitlines() in_types = False for line in lines: #print(line) if in_types: splits = line.strip().split(None, 2) if splits[0] not in ret and splits[0] in IPSET_TYPES: ret.append(splits[0]) if line.startswith("Supported set types:"): in_types = True return ret def check_type(self, type_name): """Check ipset type""" if len(type_name) > IPSET_MAXNAMELEN or type_name not in IPSET_TYPES: raise FirewallError(errors.INVALID_TYPE, "ipset type name '%s' is not valid" % type_name) def set_create(self, set_name, type_name, options=None): """Create an ipset with name, type and options""" self.check_name(set_name) self.check_type(type_name) args = [ "create", set_name, type_name ] if isinstance(options, dict): for key, val in options.items(): args.append(key) if val != "": args.append(val) return self.__run(args) def set_destroy(self, set_name): self.check_name(set_name) return self.__run([ "destroy", set_name ]) def set_add(self, set_name, entry): args = [ "add", set_name, entry ] return self.__run(args) def set_delete(self, set_name, entry): args = [ "del", set_name, entry ] return self.__run(args) def test(self, set_name, entry, options=None): args = [ "test", set_name, entry ] if options: args.append("%s" % " ".join(options)) return self.__run(args) def set_list(self, set_name=None, options=None): args = [ "list" ] if set_name: args.append(set_name) if options: args.extend(options) return self.__run(args).split("\n") def set_get_active_terse(self): """ Get active ipsets (only headers) """ lines = self.set_list(options=["-terse"]) ret = { } _name = _type = None _options = { } for line in lines: if len(line) < 1: continue pair = [ x.strip() for x in line.split(":", 1) ] if len(pair) != 2: continue elif pair[0] == "Name": _name = pair[1] elif pair[0] == "Type": _type = pair[1] elif pair[0] == "Header": splits = pair[1].split() i = 0 while i < len(splits): opt = splits[i] if opt in [ "family", "hashsize", "maxelem", "timeout", "netmask" ]: if len(splits) > i: i += 1 _options[opt] = splits[i] else: log.error("Malformed ipset list -terse output: %s", line) return { } i += 1 if _name and _type: ret[_name] = (_type, remove_default_create_options(_options)) _name = _type = None _options.clear() return ret def save(self, set_name=None): args = [ "save" ] if set_name: args.append(set_name) return self.__run(args) def set_restore(self, set_name, type_name, entries, create_options=None, entry_options=None): self.check_name(set_name) self.check_type(type_name) temp_file = tempFile() if ' ' in set_name: set_name = "'%s'" % set_name args = [ "create", set_name, type_name, "-exist" ] if create_options: for key, val in create_options.items(): args.append(key) if val != "": args.append(val) temp_file.write("%s\n" % " ".join(args)) temp_file.write("flush %s\n" % set_name) for entry in entries: if ' ' in entry: entry = "'%s'" % entry if entry_options: temp_file.write("add %s %s %s\n" % \ (set_name, entry, " ".join(entry_options))) else: temp_file.write("add %s %s\n" % (set_name, entry)) temp_file.close() stat = os.stat(temp_file.name) log.debug2("%s: %s restore %s", self.__class__, self._command, "%s: %d" % (temp_file.name, stat.st_size)) args = [ "restore" ] (status, ret) = runProg(self._command, args, stdin=temp_file.name) if log.getDebugLogLevel() > 2: try: readfile(temp_file.name) except Exception: pass else: i = 1 for line in readfile(temp_file.name): log.debug3("%8d: %s" % (i, line), nofmt=1, nl=0) if not line.endswith("\n"): log.debug3("", nofmt=1) i += 1 os.unlink(temp_file.name) if status != 0: raise ValueError("'%s %s' failed: %s" % (self._command, " ".join(args), ret)) return ret def set_flush(self, set_name): args = [ "flush" ] if set_name: args.append(set_name) return self.__run(args) def rename(self, old_set_name, new_set_name): return self.__run([ "rename", old_set_name, new_set_name ]) def swap(self, set_name_1, set_name_2): return self.__run([ "swap", set_name_1, set_name_2 ]) def version(self): return self.__run([ "version" ]) def check_ipset_name(name): """Return true if ipset name is valid""" if len(name) > IPSET_MAXNAMELEN: return False return True def remove_default_create_options(options): """ Return only non default create options """ _options = options.copy() for opt in IPSET_DEFAULT_CREATE_OPTIONS: if opt in _options and \ IPSET_DEFAULT_CREATE_OPTIONS[opt] == _options[opt]: del _options[opt] return _options def normalize_ipset_entry(entry): """ Normalize IP addresses in entry """ _entry = [] for _part in entry.split(","): try: _part.index("/") _entry.append(str(ipaddress.ip_network(_part, strict=False))) except ValueError: _entry.append(_part) return ",".join(_entry) def check_entry_overlaps_existing(entry, entries): """ Check if entry overlaps any entry in the list of entries """ # Only check simple types if len(entry.split(",")) > 1: return try: entry_network = ipaddress.ip_network(entry, strict=False) except ValueError: # could not parse the new IP address, maybe a MAC return for itr in entries: if entry_network.overlaps(ipaddress.ip_network(itr, strict=False)): raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps with existing entry '{}'".format(entry, itr)) def check_for_overlapping_entries(entries): """ Check if any entry overlaps any entry in the list of entries """ try: entries = [ipaddress.ip_network(x, strict=False) for x in entries] except ValueError: # at least one entry can not be parsed return if len(entries) == 0: return # We can take advantage of some facts of IPv4Network/IPv6Network and # how Python sorts the networks to quickly detect overlaps. # # Facts: # # 1. IPv{4,6}Network are normalized to remove host bits, e.g. # 10.1.1.0/16 will become 10.1.0.0/16. # # 2. IPv{4,6}Network objects are sorted by: # a. IP address (network bits) # then # b. netmask (significant bits count) # # Because of the above we have these properties: # # 1. big networks (netA) are sorted before smaller networks (netB) # that overlap the big network (netA) # - e.g. 10.1.128.0/17 (netA) sorts before 10.1.129.0/24 (netB) # 2. same value addresses (network bits) are grouped together even # if the number of network bits vary. e.g. /16 vs /24 # - recall that address are normalized to remove host bits # - e.g. 10.1.128.0/17 (netA) sorts before 10.1.128.0/24 (netC) # 3. non-overlapping networks (netD, netE) are always sorted before or # after networks that overlap (netB, netC) the current one (netA) # - e.g. 10.1.128.0/17 (netA) sorts before 10.2.128.0/16 (netD) # - e.g. 10.1.128.0/17 (netA) sorts after 9.1.128.0/17 (netE) # - e.g. 9.1.128.0/17 (netE) sorts before 10.1.129.0/24 (netB) # # With this we know the sorted list looks like: # # list: [ netE, netA, netB, netC, netD ] # # netE = non-overlapping network # netA = big network # netB = smaller network that overlaps netA (subnet) # netC = smaller network that overlaps netA (subnet) # netD = non-overlapping network # # If networks netB and netC exist in the list, they overlap and are # adjacent to netA. # # Checking for overlaps on a sorted list is thus: # # 1. compare adjacent elements in the list for overlaps # # Recall that we only need to detect a single overlap. We do not need to # detect them all. # entries.sort() prev_network = entries.pop(0) for current_network in entries: if prev_network.overlaps(current_network): raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps entry '{}'".format(prev_network, current_network)) prev_network = current_network PKpge[V_P)) fw_helper.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2015-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """helper backend""" __all__ = [ "FirewallHelper" ] from firewall import errors from firewall.errors import FirewallError class FirewallHelper(object): def __init__(self, fw): self._fw = fw self._helpers = { } def __repr__(self): return '%s(%r)' % (self.__class__, self._helpers) # helpers def cleanup(self): self._helpers.clear() def check_helper(self, name): if name not in self.get_helpers(): raise FirewallError(errors.INVALID_HELPER, name) def query_helper(self, name): return name in self.get_helpers() def get_helpers(self): return sorted(self._helpers.keys()) def has_helpers(self): return len(self._helpers) > 0 def get_helper(self, name): self.check_helper(name) return self._helpers[name] def add_helper(self, obj): self._helpers[obj.name] = obj def remove_helper(self, name): if name not in self._helpers: raise FirewallError(errors.INVALID_HELPER, name) del self._helpers[name] PKpge[Dprog.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2010-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import subprocess __all__ = ["runProg"] def runProg(prog, argv=None, stdin=None): if argv is None: argv = [] args = [prog] + argv input_string = None if stdin: with open(stdin, 'r') as handle: input_string = handle.read().encode() env = {'LANG': 'C'} try: process = subprocess.Popen(args, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, close_fds=True, env=env) except OSError: return (255, '') (output, err_output) = process.communicate(input_string) output = output.decode('utf-8', 'replace') return (process.returncode, output) PKpge[%% fw_ipset.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2015-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """ipset backend""" __all__ = [ "FirewallIPSet" ] from firewall.core.logger import log from firewall.core.ipset import remove_default_create_options as rm_def_cr_opts, \ normalize_ipset_entry, check_entry_overlaps_existing, \ check_for_overlapping_entries from firewall.core.io.ipset import IPSet from firewall import errors from firewall.errors import FirewallError class FirewallIPSet(object): def __init__(self, fw): self._fw = fw self._ipsets = { } def __repr__(self): return '%s(%r)' % (self.__class__, self._ipsets) # ipsets def cleanup(self): self._ipsets.clear() def check_ipset(self, name): if name not in self.get_ipsets(): raise FirewallError(errors.INVALID_IPSET, name) def query_ipset(self, name): return name in self.get_ipsets() def get_ipsets(self): return sorted(self._ipsets.keys()) def has_ipsets(self): return len(self._ipsets) > 0 def get_ipset(self, name, applied=False): self.check_ipset(name) obj = self._ipsets[name] if applied: self.check_applied_obj(obj) return obj def backends(self): backends = [] if self._fw.nftables_enabled: backends.append(self._fw.nftables_backend) if self._fw.ipset_enabled: backends.append(self._fw.ipset_backend) return backends def add_ipset(self, obj): if obj.type not in self._fw.ipset_supported_types: raise FirewallError(errors.INVALID_TYPE, "'%s' is not supported by ipset." % obj.type) self._ipsets[obj.name] = obj def remove_ipset(self, name, keep=False): obj = self._ipsets[name] if obj.applied and not keep: try: for backend in self.backends(): backend.set_destroy(name) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: log.debug1("Keeping ipset '%s' because of timeout option", name) del self._ipsets[name] def apply_ipset(self, name): obj = self._ipsets[name] for backend in self.backends(): if backend.name == "ipset": active = backend.set_get_active_terse() if name in active and ("timeout" not in obj.options or \ obj.options["timeout"] == "0" or \ obj.type != active[name][0] or \ rm_def_cr_opts(obj.options) != \ active[name][1]): try: backend.set_destroy(name) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) if self._fw._individual_calls: try: backend.set_create(obj.name, obj.type, obj.options) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: obj.applied = True if "timeout" in obj.options and \ obj.options["timeout"] != "0": # no entries visible for ipsets with timeout continue try: backend.set_flush(obj.name) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) for entry in obj.entries: try: backend.set_add(obj.name, entry) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: try: backend.set_restore(obj.name, obj.type, obj.entries, obj.options, None) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: obj.applied = True def apply_ipsets(self): for name in self.get_ipsets(): obj = self._ipsets[name] obj.applied = False log.debug1("Applying ipset '%s'" % name) self.apply_ipset(name) def flush(self): for backend in self.backends(): # nftables sets are part of the normal firewall ruleset. if backend.name == "nftables": continue for ipset in self.get_ipsets(): try: self.check_applied(ipset) backend.set_destroy(ipset) except FirewallError as msg: if msg.code != errors.NOT_APPLIED: raise msg # TYPE def get_type(self, name, applied=True): return self.get_ipset(name, applied=applied).type # DIMENSION def get_dimension(self, name): return len(self.get_ipset(name, applied=True).type.split(",")) def check_applied(self, name): obj = self.get_ipset(name) self.check_applied_obj(obj) def check_applied_obj(self, obj): if not obj.applied: raise FirewallError( errors.NOT_APPLIED, obj.name) # OPTIONS def get_family(self, name, applied=True): obj = self.get_ipset(name, applied=applied) if "family" in obj.options: if obj.options["family"] == "inet6": return "ipv6" return "ipv4" # ENTRIES def add_entry(self, name, entry): obj = self.get_ipset(name, applied=True) entry = normalize_ipset_entry(entry) IPSet.check_entry(entry, obj.options, obj.type) if entry in obj.entries: raise FirewallError(errors.ALREADY_ENABLED, "'%s' already is in '%s'" % (entry, name)) check_entry_overlaps_existing(entry, obj.entries) try: for backend in self.backends(): backend.set_add(obj.name, entry) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: if "timeout" not in obj.options or obj.options["timeout"] == "0": # no entries visible for ipsets with timeout obj.entries.append(entry) def remove_entry(self, name, entry): obj = self.get_ipset(name, applied=True) entry = normalize_ipset_entry(entry) # no entry check for removal if entry not in obj.entries: raise FirewallError(errors.NOT_ENABLED, "'%s' not in '%s'" % (entry, name)) try: for backend in self.backends(): backend.set_delete(obj.name, entry) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: if "timeout" not in obj.options or obj.options["timeout"] == "0": # no entries visible for ipsets with timeout obj.entries.remove(entry) def query_entry(self, name, entry): obj = self.get_ipset(name, applied=True) entry = normalize_ipset_entry(entry) if "timeout" in obj.options and obj.options["timeout"] != "0": # no entries visible for ipsets with timeout raise FirewallError(errors.IPSET_WITH_TIMEOUT, name) return entry in obj.entries def get_entries(self, name): obj = self.get_ipset(name, applied=True) return obj.entries def set_entries(self, name, entries): obj = self.get_ipset(name, applied=True) check_for_overlapping_entries(entries) for entry in entries: IPSet.check_entry(entry, obj.options, obj.type) if "timeout" not in obj.options or obj.options["timeout"] == "0": # no entries visible for ipsets with timeout obj.entries = entries try: for backend in self.backends(): backend.set_flush(obj.name) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: obj.applied = True try: for backend in self.backends(): if self._fw._individual_calls: for entry in obj.entries: backend.set_add(obj.name, entry) else: backend.set_restore(obj.name, obj.type, obj.entries, obj.options, None) except Exception as msg: raise FirewallError(errors.COMMAND_FAILED, msg) else: obj.applied = True return PKpge[:ےII$__pycache__/fw_policy.cpython-36.pycnu[3 g=V@sddlZddlZddlmZddlmZmZmZmZm Z m Z m Z m Z m Z mZddlmZmZmZmZmZmZmZmZmZmZmZddlmZddlmZddlm Z ddl!m"Z"dd l#m$Z$Gd d d e%Z&dS) N)log) portStr checkIPnMask checkIP6nMask checkProtocolenable_ip_forwardingcheck_single_addressportInPortRangeget_nf_conntrack_short_namecoalescePortRangebreakPortRange) Rich_Rule Rich_Accept Rich_Service Rich_Port Rich_ProtocolRich_MasqueradeRich_ForwardPortRich_SourcePortRich_IcmpBlock Rich_IcmpType Rich_Mark)FirewallTransaction)errors) FirewallError)LastUpdatedOrderedDict)SOURCE_IPSET_TYPESc@seZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ d ddZddZddZddZd d d!Zd d"d#Zdd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zdd0d1Zd2d3Zdd4d5Zd6d7Zd8d9Zd:d;Zdd?Z dd@dAZ!dBdCZ"ddDdEZ#dFdGZ$dHdIZ%dJdKZ&dLdMZ'dNdOZ(dPdQZ)dRdSZ*ddTdUZ+dVdWZ,ddXdYZ-dZd[Z.d\d]Z/d^d_Z0d`daZ1dbdcZ2ddddeZ3dfdgZ4ddhdiZ5djdkZ6dldmZ7dndoZ8dpdqZ9drdsZ:dtduZ;dvdwZ<ddxdyZ=dzd{Z>dd|d}Z?d~dZ@ddZAddZBddZCddZDdddZEddZFdddZGddZHddZIddZJddZKdddZLddZMdddZNddZOddZPddZQddZRdddZSddZTdddZUddZVddZWdddZXd ddZYd!ddZZddZ[d"ddZ\ddZ]d#ddZ^ddZ_ddZ`ddZad$ddÄZbddńZcd%ddDŽZdddɄZedd˄Zfdd̈́ZgddτZhd&ddфZiddӄZjddՄZkd'ddׄZlddلZmddۄZndd݄Zodd߄ZpddZqddZrddZsddZtddZud(ddZvd)ddZwddZxddZyddZzddZ{d*ddZ|ddZ}ddZ~ddZddZddZddZddZddZd+d d ZdS(,FirewallPolicycCs||_i|_i|_dS)N)_fw_chains _policies)selffwr#/usr/lib/python3.6/fw_policy.py__init__szFirewallPolicy.__init__cCsd|j|j|jfS)Nz %s(%r, %r)) __class__rr )r!r#r#r$__repr__szFirewallPolicy.__repr__cCs|jj|jjdS)N)rclearr )r!r#r#r$cleanups zFirewallPolicy.cleanupcCs t|jS)N)rr)r!r#r#r$new_transaction$szFirewallPolicy.new_transactioncCst|jjS)N)sortedr keys)r!r#r#r$ get_policies)szFirewallPolicy.get_policiescCs8g}x*|jD]}|j|}|js|j|qWt|S)N)r- get_policyderived_from_zoneappendr+)r!Zpoliciespp_objr#r#r$"get_policies_not_derived_from_zone,s  z1FirewallPolicy.get_policies_not_derived_from_zonecCs~g}xt|jD]h}|j|}t|dt|jjjtddgB@rt|dt|jjjtddgB@r|j|qW|S)N ingress_zonesHOSTANY egress_zones)r3 get_settingssetrzoneZget_active_zonesr0)r!Zactive_policiespolicysettingsr#r#r$)get_active_policies_not_derived_from_zone4s ((z8FirewallPolicy.get_active_policies_not_derived_from_zonecCs|jj|}|j|S)N)r check_policyr )r!r;r1r#r#r$r.>s zFirewallPolicy.get_policyc Cs,dddD|_||j|j<|j|jdS)NcSsi|] }t|qSr#)r).0xr#r#r$ Csz-FirewallPolicy.add_policy..servicesports masquerade forward_ports source_ports icmp_blocksrules protocolsicmp_block_inversionr4r7) rBrCrDrErFrGrHrIrJr4r7)r<r namecopy_permanent_to_runtime)r!objr#r#r$ add_policyBs  zFirewallPolicy.add_policycCs0|j|}|jr|j||jj|j|=dS)N)r appliedunapply_policy_settingsr<r()r!r;rMr#r#r$ remove_policyNs    zFirewallPolicy.remove_policycCs|j|}|jrdSx|jD]}|j||ddqWx|jD]}|j||ddqr rOr*r/%_get_table_chains_for_policy_dispatch#_get_table_chains_for_zone_dispatchgen_chain_rulesr8_ingress_egress_zones _icmp_block _forward_port_service_port _protocol _source_port _masquerade_FirewallPolicy__ruler rr[execute) r!enabler;rb_policyrM transactiontablechainr<keyr`r#r#r$_policy_settingssj                zFirewallPolicy._policy_settingscCs|jd||ddS)NT)rb)r)r!r;rbr#r#r$rcsz$FirewallPolicy.apply_policy_settingscCs|jd||ddS)NF)rb)r)r!r;rbr#r#r$rPsz&FirewallPolicy.unapply_policy_settingsc Csr|j|j}|j||j||j||j||j||j||j||j ||j ||j |d }|j j ||S)zH :return: exported config updated with runtime settings ) rBrCrGrDrE rich_rulesrIrFr4r7)r.Zexport_config_dict list_services list_portslist_icmp_blocksquery_masqueradelist_forward_ports list_ruleslist_protocolslist_source_portslist_ingress_zoneslist_egress_zonesrZ'combine_runtime_with_permanent_settings)r!r;Z permanentZruntimer#r#r$get_config_with_settings_dictsz,FirewallPolicy.get_config_with_settings_dictc sddlmd fdd }fdd}jjfjjfjjfjj fj j f||fj j fjjfjjfjjfd }j|}jj||\}} xt| D]l} t| | trxV| | D]8} t| tr|| d|f| q|| d|| qWq|| d|qWx|D]} t|| trxn|| D]J} t| trv|| d|f| d|d n|| d|| d|d qFWn|| d|d|d q(WdS) Nr)r csj||dd|ddS)N)rkr)rgrf)r^)r;rkrgrf)r r!r#r$add_rule_wrapperszFFirewallPolicy.set_config_with_settings_dict..add_rule_wrappercsj||ddS)N)rk) remove_rule)r;rk)r r!r#r$remove_rule_wrapperszIFirewallPolicy.set_config_with_settings_dict..remove_rule_wrapper) rBrCrGrDrErrIrFr4r7rj)rgrf)rN)firewall.core.richr rWremove_servicerX remove_portrUremove_icmp_blockr_remove_masqueraderVremove_forward_portr\remove_protocolr]remove_source_portrSremove_ingress_zonerTremove_egress_zonerrZget_added_and_removed_settings isinstancelisttuple) r!r;r<rfrrZ setting_to_fnZ old_settingsZ add_settingsZremove_settingsr~r`r#)r r!r$set_config_with_settings_dicts:                z,FirewallPolicy.set_config_with_settings_dictcCs&|sttj|dkr"|jj|dS)Nr5r6)r5r6)rr INVALID_ZONEr check_zone)r!r:r#r#r$check_ingress_zones z!FirewallPolicy.check_ingress_zonecCs|j||S)N)r)r!r:r#r#r$Z__ingress_zone_id"s z FirewallPolicy.__ingress_zone_idrTc Cs|jj|}|jj||jj|j|}|j|} | |jdkrXttj d||fd|jdksd|jdks|d kr|jdrttj d|dkrd|jdkrttj d|dkr|j } n|} |rJ|j r|j d|| |j|| ||| j|j|| |j s:||jkrH|j|| d | j|j|dn|j d || n |j|| ||| j|j|| |dkr~| jd dS) Nr4z'%s' already in '%s'r6r5zI'ingress-zones' may only contain one of: many regular zones, ANY, or HOSTr7zF'HOST' can only appear in either ingress or egress zones, but not bothF)rbT)r6r5)rr> check_timeout check_panicr _FirewallPolicy__ingress_zone_idr<rrrZrr*rOro&_FirewallPolicy__register_ingress_zoneadd_fail(_FirewallPolicy__unregister_ingress_zoner=rcrerx) r!r;r:rgrfrbrRrz_objzone_idr{r#r#r$rS&s<         zFirewallPolicy.add_ingress_zonecCs|j|||jd|<dS)Nr4)_FirewallPolicy__gen_settingsr<)r!rrrgrfr#r#r$Z__register_ingress_zoneSsz&FirewallPolicy.__register_ingress_zonecCs|jj|}|jj|j|}|j|}||jdkrLttjd||f|dkr^|j }n|}|j rt |jddkr|j ||n|j d|||j|||j|j||dd||jkr|j d||n|j|j|||dkr|jd|S)Nr4z'%s' not in '%s'rjFT)rr>rr rr<rr NOT_ENABLEDr*rOlenrProrrrr=add_postrx)r!r;r:rbrzrrr{r#r#r$rVs,        z"FirewallPolicy.remove_ingress_zonecCs||jdkr|jd|=dS)Nr4)r<)r!rrr#r#r$Z__unregister_ingress_zoneysz(FirewallPolicy.__unregister_ingress_zonecCs|j||j|dkS)Nr4)rr8)r!r;r:r#r#r$query_ingress_zone}sz!FirewallPolicy.query_ingress_zonecCst|j|djS)Nr4)rr8r,)r!r;r#r#r$rsz!FirewallPolicy.list_ingress_zonescCs&|sttj|dkr"|jj|dS)Nr5r6)r5r6)rrrrr)r!r:r#r#r$check_egress_zones z FirewallPolicy.check_egress_zonecCs|j||S)N)r)r!r:r#r#r$Z__egress_zone_ids zFirewallPolicy.__egress_zone_idc Cs|jj|}|jj||jj|j|}|j|} | |jdkrXttj d||fd|jdksd|jdks|d kr|jdrttj d|dkrd|jdkrttj d|dkr|j } n|} |rJ|j r|j d|| |j|| ||| j|j|| |j s:||jkrH|j|| d | j|j|dn|j d || n |j|| ||| j|j|| |dkr~| jd dS) Nr7z'%s' already in '%s'r6r5zH'egress-zones' may only contain one of: many regular zones, ANY, or HOSTr4zF'HOST' can only appear in either ingress or egress zones, but not bothF)rbT)r6r5)rr>rrr _FirewallPolicy__egress_zone_idr<rrrZrr*rOro%_FirewallPolicy__register_egress_zoner'_FirewallPolicy__unregister_egress_zoner=rcrerx) r!r;r:rgrfrbrRrzrrr{r#r#r$rTs<         zFirewallPolicy.add_egress_zonecCs|j|||jd|<dS)Nr7)rr<)r!rrrgrfr#r#r$Z__register_egress_zonesz%FirewallPolicy.__register_egress_zonecCs|jj|}|jj|j|}|j|}||jdkrLttjd||f|dkr^|j }n|}|j rt |jddkr|j ||n|j d|||j|||j|j||dd||jkr|j d||n|j|j|||dkr|jd|S)Nr7z'%s' not in '%s'rjFT)rr>rr rr<rrrr*rOrrProrrrr=rrx)r!r;r:rbrzrrr{r#r#r$rs,        z!FirewallPolicy.remove_egress_zonecCs||jdkr|jd|=dS)Nr7)r<)r!rrr#r#r$Z__unregister_egress_zonesz'FirewallPolicy.__unregister_egress_zonecCs|j||j|dkS)Nr7)rr8)r!r;r:r#r#r$query_egress_zonesz FirewallPolicy.query_egress_zonecCst|j|djS)Nr7)rr8r,)r!r;r#r#r$rsz FirewallPolicy.list_egress_zonescCs |jdS)N)Zcheck)r!ruler#r#r$ check_ruleszFirewallPolicy.check_rulecCs|j|t|S)N)rstr)r!rr#r#r$Z __rule_ids zFirewallPolicy.__rule_idcCsx|sdS|jr,t|jrdSt|jrtdSnHt|dr@|jr@dSt|drt|jrt|j|j|j|j|j|jSdS)Nipv4ipv6macipset) Zaddrrrhasattrrr_check_ipset_type_for_source_check_ipset_applied _ipset_family)r!sourcer#r#r$_rule_source_ipvs     zFirewallPolicy._rule_source_ipvcCs|j||||dS)N) _rule_prepare)r!ryr;rr{r#r#r$Z__ruleszFirewallPolicy.__rulec CsL|jj|}|jj||jj|j|}|j|}||jdkrh|jrP|jn|} tt j d|| f|js|j rt |j t rd|jdkrtt jdd|jdkrtt jdx6|jdD](} | dkrq|jjj| rtt jd qW|j rt |j trd|jdkr,|j jrtt jd nb|jdr|j jsNtt jd x>|jdD]0} | dkrlqZ|jjj| rZtt jd qZW|jrt |jtrx>|jdD]0} | dkrq|jjj| rtt jd qW|dkr|j} n|} |jr|jd||| |j||||| j|j|||dkrH| jd|S)NrHz'%s' already in '%s'r5r7z.'masquerade' is invalid for egress zone 'HOST'r4z/'masquerade' is invalid for ingress zone 'HOST'r6zR'masquerade' cannot be used in a policy if an ingress zone has assigned interfaceszAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zonezS'forward-port' cannot be used in a policy if an egress zone has assigned interfaceszR'mark' action cannot be used in a policy if an egress zone has assigned interfacesT)r6r5)rr>rrr _FirewallPolicy__rule_idr<r/rrrZelementrrrr:list_interfacesr to_addressINVALID_FORWARDactionrr*rOrw_FirewallPolicy__register_ruler _FirewallPolicy__unregister_rulerx) r!r;rrgrfrbrzrrule_id_namer:r{r#r#r$r^ s`                 zFirewallPolicy.add_rulecCs|j|||jd|<dS)NrH)rr<)r!rrrgrfr#r#r$Z__register_ruleEszFirewallPolicy.__register_rulec Cs|jj|}|jj|j|}|j|}||jdkr\|jrD|jn|}ttj d||f|dkrn|j }n|}|j r|j d||||j |j|||dkr|jd|S)NrHz'%s' not in '%s'FT)rr>rr rr<r/rrrr*rOrwrrrx) r!r;rrbrzrrrr{r#r#r$rIs"      zFirewallPolicy.remove_rulecCs||jdkr|jd|=dS)NrH)r<)r!rrr#r#r$Z__unregister_ruledsz FirewallPolicy.__unregister_rulecCs|j||j|dkS)NrH)rr8)r!r;rr#r#r$ query_rulehszFirewallPolicy.query_rulecCst|j|djS)NrH)rr8r,)r!r;r#r#r$rkszFirewallPolicy.list_rulescCs|jj|dS)N)r check_service)r!servicer#r#r$rpszFirewallPolicy.check_servicecCs|j||S)N)r)r!rr#r#r$Z __service_idss zFirewallPolicy.__service_idc Cs|jj|}|jj||jj|j|}|j|}||jdkrh|jrP|jn|} tt j d|| f|dkrz|j } n|} |j r|j d||| |j||||| j|j|||dkr| jd|S)NrBz'%s' already in '%s'T)rr>rrr _FirewallPolicy__service_idr<r/rrrZr*rOrr!_FirewallPolicy__register_servicer#_FirewallPolicy__unregister_servicerx) r!r;rrgrfrbrzr service_idrr{r#r#r$rWws&       zFirewallPolicy.add_servicecCs|j|||jd|<dS)NrB)rr<)r!rrrgrfr#r#r$Z__register_servicesz!FirewallPolicy.__register_servicec Cs|jj|}|jj|j|}|j|}||jdkr\|jrD|jn|}ttj d||f|dkrn|j }n|}|j r|j d||||j |j|||dkr|jd|S)NrBz'%s' not in '%s'FT)rr>rr rr<r/rrrr*rOrrrrrx) r!r;rrbrzrrrr{r#r#r$rs"      zFirewallPolicy.remove_servicecCs||jdkr|jd|=dS)NrB)r<)r!rrr#r#r$Z__unregister_servicesz#FirewallPolicy.__unregister_servicecCs|j||j|dkS)NrB)rr8)r!r;rr#r#r$ query_serviceszFirewallPolicy.query_servicecCs|j|djS)NrB)r8r,)r!r;r#r#r$rszFirewallPolicy.list_servicesc CsTg}xJ|D]B}y|jjj|}Wn tk r@ttj|YnX|j|q W|S)N)rhelper get_helperrrINVALID_HELPERr0)r!helpers_helpersr_helperr#r#r$get_helpers_for_service_helperss z.FirewallPolicy.get_helpers_for_service_helperscCsg}x|D]}y|jjj|}Wn tk r@ttj|YnXt|jdkrt|j }y|jjj|}|j |Wqtk r|rt j d|w YqXq |j |q W|S)NrjzHelper '%s' is not available) rrrrrrrrCr moduler0rr[)r!modulesryrrr_module_short_namerr#r#r$get_helpers_for_service_moduless"   z.FirewallPolicy.get_helpers_for_service_modulescCs|jj||jj|dS)N)r check_port check_tcpudp)r!portprotocolr#r#r$rs zFirewallPolicy.check_portcCs|j||t|d|fS)N-)rr)r!rrr#r#r$Z __port_ids zFirewallPolicy.__port_idcs|jj|}|jj||jj|j|}ttfdd|jd} x@| D]8} t|| drN|j rl|j n|} t t j d|| fqNWt |dd| D\} } |dkr|j}n|}|jr x$| D]}|jd|t|d |qWx$| D]}|jd |t|d |qWx:| D]2}|j|} |j|| |||j|j|| qWx*| D]"}|j|} |j|j|| qNW|dkr|jd|S) Ncs |dkS)Nrjr#)r@)rr#r$sz)FirewallPolicy.add_port..rCrz'%s:%s' already in '%s'cSsg|] \}}|qSr#r#)r?rsrtr#r#r$ sz+FirewallPolicy.add_port..TrF)rr>rrr rfilterr<r r/rrrZr r*rOrsr_FirewallPolicy__port_id_FirewallPolicy__register_portr _FirewallPolicy__unregister_portrrx)r!r;rrrgrfrbrzrexisting_port_idsport_idr added_rangesremoved_rangesr{ranger#)rr$rXs:              zFirewallPolicy.add_portcCs|j|||jd|<dS)NrC)rr<)r!rrrgrfr#r#r$Z__register_portszFirewallPolicy.__register_portcs|jj|}|jj|j|}ttfdd|jd}xB|D]}t||drBPqBW|jrf|jn|} t t j d|| ft |dd|D\} } |dkr|j } n|} |jrx$| D]} |jd|t| d | qWx$| D]} |jd |t| d | qWx:| D]2} |j| }|j||dd| j|j||qWx*| D]"} |j| }| j|j||qDW|dkr~| jd|S) Ncs |dkS)Nrjr#)r@)rr#r$rsz,FirewallPolicy.remove_port..rCrz'%s:%s' not in '%s'cSsg|] \}}|qSr#r#)r?rsrtr#r#r$r#sz.FirewallPolicy.remove_port..TrF)rr>rr rrr<r r/rrrr r*rOrsrrrrrrrx)r!r;rrrbrzrrrrrrr{rr#)rr$rs:             zFirewallPolicy.remove_portcCs||jdkr|jd|=dS)NrC)r<)r!rrr#r#r$Z__unregister_port=sz FirewallPolicy.__unregister_portcCs6x0|j|dD]\}}t||r||krdSqWdS)NrCTF)r8r )r!r;rrrsrtr#r#r$ query_portAszFirewallPolicy.query_portcCst|j|djS)NrC)rr8r,)r!r;r#r#r$rHszFirewallPolicy.list_portscCst|sttj|dS)N)rrrZINVALID_PROTOCOL)r!rr#r#r$check_protocolMszFirewallPolicy.check_protocolcCs|j||S)N)r)r!rr#r#r$Z __protocol_idQs zFirewallPolicy.__protocol_idc Cs|jj|}|jj||jj|j|}|j|}||jdkrh|jrP|jn|} tt j d|| f|dkrz|j } n|} |j r|j d||| |j||||| j|j|||dkr| jd|S)NrIz'%s' already in '%s'T)rr>rrr _FirewallPolicy__protocol_idr<r/rrrZr*rOrt"_FirewallPolicy__register_protocolr$_FirewallPolicy__unregister_protocolrx) r!r;rrgrfrbrzr protocol_idrr{r#r#r$r\Us&       zFirewallPolicy.add_protocolcCs|j|||jd|<dS)NrI)rr<)r!rrrgrfr#r#r$Z__register_protocolrsz"FirewallPolicy.__register_protocolc Cs|jj|}|jj|j|}|j|}||jdkr\|jrD|jn|}ttj d||f|dkrn|j }n|}|j r|j d||||j |j|||dkr|jd|S)NrIz'%s' not in '%s'FT)rr>rr rr<r/rrrr*rOrtrrrx) r!r;rrbrzrrrr{r#r#r$rvs$       zFirewallPolicy.remove_protocolcCs||jdkr|jd|=dS)NrI)r<)r!rrr#r#r$Z__unregister_protocolsz$FirewallPolicy.__unregister_protocolcCs|j||j|dkS)NrI)rr8)r!r;rr#r#r$query_protocolszFirewallPolicy.query_protocolcCst|j|djS)NrI)rr8r,)r!r;r#r#r$rszFirewallPolicy.list_protocolscCs|j||t|d|fS)Nr)rr)r!rrr#r#r$Z__source_port_ids zFirewallPolicy.__source_port_idcs|jj|}|jj||jj|j|}ttfdd|jd} x@| D]8} t|| drN|j rl|j n|} t t j d|| fqNWt |dd| D\} } |dkr|j}n|}|jr x$| D]}|jd|t|d |qWx$| D]}|jd |t|d |qWx:| D]2}|j|} |j|| |||j|j|| qWx*| D]"}|j|} |j|j|| qNW|dkr|jd|S) Ncs |dkS)Nrjr#)r@)rr#r$rsz0FirewallPolicy.add_source_port..rFrz'%s:%s' already in '%s'cSsg|] \}}|qSr#r#)r?rsrtr#r#r$rsz2FirewallPolicy.add_source_port..TrF)rr>rrr rrr<r r/rrrZr r*rOrur_FirewallPolicy__source_port_id%_FirewallPolicy__register_source_portr'_FirewallPolicy__unregister_source_portrrx)r!r;rrrgrfrbrzrrrrrrr{rr#)rr$r]s:              zFirewallPolicy.add_source_portcCs|j|||jd|<dS)NrF)rr<)r!rrrgrfr#r#r$Z__register_source_portsz%FirewallPolicy.__register_source_portcs|jj|}|jj|j|}ttfdd|jd}xB|D]}t||drBPqBW|jrf|jn|} t t j d|| ft |dd|D\} } |dkr|j } n|} |jrx$| D]} |jd|t| d | qWx$| D]} |jd |t| d | qWx:| D]2} |j| }|j||dd| j|j||qWx*| D]"} |j| }| j|j||qDW|dkr~| jd|S) Ncs |dkS)Nrjr#)r@)rr#r$rsz3FirewallPolicy.remove_source_port..rFrz'%s:%s' not in '%s'cSsg|] \}}|qSr#r#)r?rsrtr#r#r$rsz5FirewallPolicy.remove_source_port..TrF)rr>rr rrr<r r/rrrr r*rOrurrrrrrrx)r!r;rrrbrzrrrrrrr{rr#)rr$rs:             z!FirewallPolicy.remove_source_portcCs||jdkr|jd|=dS)NrF)r<)r!rrr#r#r$Z__unregister_source_portsz'FirewallPolicy.__unregister_source_portcCs6x0|j|dD]\}}t||r||krdSqWdS)NrFTF)r8r )r!r;rrrsrtr#r#r$query_source_portsz FirewallPolicy.query_source_portcCst|j|djS)NrF)rr8r,)r!r;r#r#r$rsz FirewallPolicy.list_source_portscCsdS)NTr#)r!r#r#r$Z__masquerade_idszFirewallPolicy.__masquerade_idc Cs8|jj|}|jj||jj|j|}|j}||jdkrb|jrN|jn|}tt j d||jsd|jdkrtt j dd|jdkrtt j dx6|jdD](} | dkrq|jj j | rtt j d qW|dkr|j} n|} |jr|jd || |j||||| j|j|||dkr4| jd |S) NrDz"masquerade already enabled in '%s'r5r7z.'masquerade' is invalid for egress zone 'HOST'r4z/'masquerade' is invalid for ingress zone 'HOST'r6zR'masquerade' cannot be used in a policy if an ingress zone has assigned interfacesT)rr>rrr _FirewallPolicy__masquerade_idr<r/rrrZrr:rr*rOrv$_FirewallPolicy__register_masquerader&_FirewallPolicy__unregister_masqueraderx) r!r;rgrfrbrzr masquerade_idrr:r{r#r#r$r_ s:          zFirewallPolicy.add_masqueradecCs|j|||jd|<dS)NrD)rr<)r!rrrgrfr#r#r$Z__register_masquerade2sz$FirewallPolicy.__register_masqueradecCs|jj|}|jj|j|}|j}||jdkrV|jrB|jn|}ttj d||dkrh|j }n|}|j r|j d|||j |j|||dkr|jd|S)NrDzmasquerade not enabled in '%s'FT)rr>rr rr<r/rrrr*rOrvrrrx)r!r;rbrzrrrr{r#r#r$r6s"      z FirewallPolicy.remove_masqueradecCs||jdkr|jd|=dS)NrD)r<)r!rrr#r#r$Z__unregister_masqueradePsz&FirewallPolicy.__unregister_masqueradecCs|j|j|dkS)NrD)rr8)r!r;r#r#r$rTszFirewallPolicy.query_masqueradecCs^|jj||jj||r(|jj||rBt||sBttj|| rZ| rZttjddS)Nz.port-forwarding is missing to-port AND to-addr)rrrrrrZ INVALID_ADDRr)r!ipvrrtoporttoaddrr#r#r$check_forward_portYs      z!FirewallPolicy.check_forward_portcCsLtd|r|jd||||n|jd||||t|d|t|dt|fS)Nrrr)rrrr)r!rrrrr#r#r$Z__forward_port_idfs   z FirewallPolicy.__forward_port_idc CsZ|jj|} |jj||jj|j| } |j||||} | | jdkrt| jrV| jn| } tt j d||||| f| jsd| jdkr|rtt j dnR| jdr|stt j dx6| jdD](} | dkrq|jj j | rtt jdqW|dkr|j}n|}| jr"|jd | ||||||j| | |||j|j| | |dkrV|jd | S) NrEz'%s:%s:%s:%s' already in '%s'r5r7zAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zoner6zS'forward-port' cannot be used in a policy if an egress zone has assigned interfacesT)rr>rrr _FirewallPolicy__forward_port_idr<r/rrrZrr:rrr*rOrq&_FirewallPolicy__register_forward_portr(_FirewallPolicy__unregister_forward_portrx)r!r;rrrrrgrfrbrzr forward_idrr:r{r#r#r$rVnsB          zFirewallPolicy.add_forward_portcCs|j|||jd|<dS)NrE)rr<)r!rrrgrfr#r#r$Z__register_forward_portsz&FirewallPolicy.__register_forward_portc Cs|jj|}|jj|j|}|j||||} | |jdkrh|jrJ|jn|} ttj d||||| f|dkrz|j } n|} |j r|j d|| ||||| j |j|| |dkr| jd|S)NrEz'%s:%s:%s:%s' not in '%s'FT)rr>rr rr<r/rrrr*rOrqrrrx) r!r;rrrrrbrzrrrr{r#r#r$rs&     z"FirewallPolicy.remove_forward_portcCs||jdkr|jd|=dS)NrE)r<)r!rrr#r#r$Z__unregister_forward_portsz(FirewallPolicy.__unregister_forward_portcCs"|j||||}||j|dkS)NrE)rr8)r!r;rrrrrr#r#r$query_forward_portsz!FirewallPolicy.query_forward_portcCst|j|djS)NrE)rr8r,)r!r;r#r#r$rsz!FirewallPolicy.list_forward_portscCs|jj|dS)N)rZcheck_icmptype)r!icmpr#r#r$check_icmp_blockszFirewallPolicy.check_icmp_blockcCs|j||S)N)r)r!rr#r#r$Z__icmp_block_ids zFirewallPolicy.__icmp_block_idc Cs|jj|}|jj||jj|j|}|j|}||jdkrh|jrP|jn|} tt j d|| f|dkrz|j } n|} |j r|j d||| |j||||| j|j|||dkr| jd|S)NrGz'%s' already in '%s'T)rr>rrr _FirewallPolicy__icmp_block_idr<r/rrrZr*rOrp$_FirewallPolicy__register_icmp_blockr&_FirewallPolicy__unregister_icmp_blockrx) r!r;rrgrfrbrzricmp_idrr{r#r#r$rUs&       zFirewallPolicy.add_icmp_blockcCs|j|||jd|<dS)NrG)rr<)r!rr rgrfr#r#r$Z__register_icmp_blocksz$FirewallPolicy.__register_icmp_blockc Cs|jj|}|jj|j|}|j|}||jdkr\|jrD|jn|}ttj d||f|dkrn|j }n|}|j r|j d||||j |j|||dkr|jd|S)NrGz'%s' not in '%s'FT)rr>rr rr<r/rrrr*rOrprr rx) r!r;rrbrzrr rr{r#r#r$rs"      z FirewallPolicy.remove_icmp_blockcCs||jdkr|jd|=dS)NrG)r<)r!rr r#r#r$Z__unregister_icmp_block sz&FirewallPolicy.__unregister_icmp_blockcCs|j||j|dkS)NrG)rr8)r!r;rr#r#r$query_icmp_blockszFirewallPolicy.query_icmp_blockcCs|j|djS)NrG)r8r,)r!r;r#r#r$rszFirewallPolicy.list_icmp_blockscCsdS)NTr#)r!r#r#r$Z__icmp_block_inversion_idsz(FirewallPolicy.__icmp_block_inversion_idc Cs|jj|}|jj|j|}|j}||jdkrV|jrB|jn|}ttj d||dkrh|j }n|}|j rx&|j |dD]} |j d|| |qW|jd|||j||||j|j||||j rx&|j |dD]} |j d|| |qW|jd|||dkr|jd|S)NrJz,icmp-block-inversion already enabled in '%s'rGFT)rr>rr (_FirewallPolicy__icmp_block_inversion_idr<r/rrrZr*rOr8rp_icmp_block_inversion._FirewallPolicy__register_icmp_block_inversionr*_FirewallPolicy__undo_icmp_block_inversionrx) r!r;rfrbrzricmp_block_inversion_idrr{r`r#r#r$add_icmp_block_inversions6        z'FirewallPolicy.add_icmp_block_inversioncCs|jd||jd|<dS)NrrJ)rr<)r!rrrfr#r#r$Z__register_icmp_block_inversionEsz.FirewallPolicy.__register_icmp_block_inversioncCs|j}|jr6x&|j|dD]}|jd|||qW||jdkrP|jd|=|jr~x&|j|dD]}|jd|||qfW|jddS)NrGFrJT)r*rOr8rpr<rx)r!rzrrr{r`r#r#r$Z__undo_icmp_block_inversionJs z*FirewallPolicy.__undo_icmp_block_inversionc Cs|jj|}|jj|j|}|j}||jdkrV|jrB|jn|}ttj d||dkrh|j }n|}|j rx&|j |dD]}|j d|||qW|jd|||j|||j|j||d|j rx&|j |dD]}|j d|||qW|jd|||dkr|jd|S)NrJz(icmp-block-inversion not enabled in '%s'rGFT)rr>rr r r<r/rrrr*rOr8rpr0_FirewallPolicy__unregister_icmp_block_inversionrrrx) r!r;rbrzrrrr{r`r#r#r$remove_icmp_block_inversion\s6        z*FirewallPolicy.remove_icmp_block_inversioncCs||jdkr|jd|=dS)NrJ)r<)r!rrr#r#r$Z!__unregister_icmp_block_inversionsz0FirewallPolicy.__unregister_icmp_block_inversioncCs|j|j|dkS)NrJ)r r8)r!r;r#r#r$query_icmp_block_inversionsz)FirewallPolicy.query_icmp_block_inversionc Cs|jjj|}|jr*|jjj|jd}n|}|rT||jkrt||f|j|krtdSn ||jksp||f|j|krtdSx@|jjD]2}|jr||j kr|j ||||} |j || qW|j ||||fg|j |j || ||fgdS)Nr)rr;r.r/r:Z_zone_policiesrenabled_backendspolicies_supportedZget_available_tablesZbuild_policy_chain_rules add_rules_register_chainsr) r!r;creater|r}r{rMZtracking_policybackendrHr#r#r$rns$   zFirewallPolicy.gen_chain_rulescCsbx\|D]T\}}|r,|jj|gj||fq|j|j||ft|j|dkr|j|=qWdS)Nr)r setdefaultr0remover)r!r;rZtablesr|r}r#r#r$rs zFirewallPolicy._register_chainscCs$|jjj|dkrdS|jjj|S)Nzhash:mac)rrget_typeZ get_family)r!rKr#r#r$rszFirewallPolicy._ipset_familycCs|jjj|S)N)rrr)r!rKr#r#r$Z __ipset_typeszFirewallPolicy.__ipset_typecCsdj|g|jjj|S)N,)joinrrZ get_dimension)r!rKflagr#r#r$_ipset_match_flagssz!FirewallPolicy._ipset_match_flagscCs|jjj|S)N)rrZ check_applied)r!rKr#r#r$rsz#FirewallPolicy._check_ipset_appliedcCs*|j|}|tkr&ttjd||fdS)Nz.ipset '%s' with type '%s' not usable as source)_FirewallPolicy__ipset_typerrrZ INVALID_IPSET)r!rKZ_typer#r#r$rs  z+FirewallPolicy._check_ipset_type_for_sourcec st|jtkrjjj|jj}|dkr2|jjg}xR|jD]H}||krHq:j||j |t j |}||j_j |||||dq:Wg} |j r|j g} nH|jrt|jtst|jtrjjj|jjjrfdddD} j|j} | r&|j r |j | kr&ttjd| |j fn| g} | s4ddg} fdd| D} | |_x2tfdd| DD]} t|jtkrjjj|jj}g} t|jd kr|jrttjd xB| D].} | |jkr| j| r| j |j| qWn | j dx~| D]}t|jtkrj|j |}|j!|j"7}t#t|d d d }g}x|D]}|j$}t%|}|j&dd}|j ||j dkr| j|j  rqTt|j'dkr|j |n:x8|j'D].\}}| j(||||||j|}|j)| |qWqTW|j*|x4|j'D]*\}}| j+||||||}|j)| |q Wx.|j,D]$}| j-|||||}|j)| |q@Wx4|j.D]*\}}| j/||||||}|j)| |qpWqWqft|jt0kr|jj1}|jj2}j3||| j+||||d|}|j)| |qft|jt4kr<|jj5}j6|| j-|||d|}|j)| |qft|jt7kr|rzx&| D]} | j| rX|j8t9| qXW| j:|||}|j)| |qft|jt;kr4|jj1}|jj2}|jj<}|jj=}xD| D]<} | j| rj>| |||||r|r|j8t9| qW| j?|||||||}|j)| |qft|jt@kr|jj1}|jj2}j3||| j/||||d|}|j)| |nt|jtkst|jtkr>jjj|jj|j rjr|j jkrttjAd|j |jjft|jtkr |jr t|jtkr ttjd| jB|||}|j)| |n>|jdkrf| jC|||}|j)| |nttjdt|jqfWdS)N)included_servicescsg|]}|jkr|qSr#) destination)r?r)ictr#r$rsz0FirewallPolicy._rule_prepare..rrz;Source address family '%s' conflicts with rule family '%s'.csg|]}jj|r|qSr#)ris_ipv_enabled)r?r)r!r#r$rscsg|]}jj|qSr#)rget_backend_by_ipv)r?r@)r!r#r$rsrz"Destination conflict with service.cSs|jS)N)rK)r@r#r#r$rsz.FirewallPolicy._rule_prepare..)r~ conntracknatrrjz3rich rule family '%s' conflicts with icmp type '%s'z'IcmpBlock not usable with accept actionzUnknown element %s)rr)Dtyperrrr get_servicerKincludesrr0copydeepcopyrfamilyrrrconfig get_icmptyper%rrrrZ INVALID_RULEipvsr9ris_ipv_supportedrrrrrrr+rr replacerCbuild_policy_helper_ports_rulesrZ add_modulesbuild_policy_ports_rulesrIbuild_policy_protocol_rulesrFbuild_policy_source_ports_rulesrrrrrvaluerrrrbuild_policy_masquerade_rulesrZto_portrrbuild_policy_forward_port_rulesrZINVALID_ICMPTYPEbuild_policy_icmp_block_rulesZ*build_policy_rich_source_destination_rules)r!ryr;rr{r$svcincludeZ_ruler3Z source_ipvrZ destinationsrr%rrrrr nat_modulerprotorHrrrr#)r&r!r$rs                             zFirewallPolicy._rule_preparec Csb|jjj|}|j|j|}||j|j7}tt|ddd}|dkrN|g}x@|j D]6}||krdqV|j ||j ||j |||||dqVWg} xnd D]f} |jj | sq|jj| } t|jdkr| |jkr| j | |j| fq| df| kr| j | dfqWxV| D]L\} } x|D]} | j}t|}| jjdd }|j|| jd krf| j| j rfqt| jd kr|j|n:x8| jD].\}}| j||||| | j|}|j| |qWqWx2|jD](\}}| j||||| }|j| |qWx,|jD]"}| j|||| }|j| |qWx2|jD](\}}| j||||| }|j| |q,Wq WdS) NcSs|jS)N)rK)r@r#r#r$rsz)FirewallPolicy._service..)r~)r$rrrr)r*rrj)rr) rrr,rrrrr+r9r-rr0rrr'r(rr%rr r5Z add_moduler0r4rCr6rKrr7rIr8rFr9)r!ryr;rr{r$r>rr?Z backends_ipvrrr%rrrr@rrArHrr#r#r$rrsb               zFirewallPolicy._servicecCs<x6|jjD](}|jsq |j||||}|j||q WdS)N)rrrr7r)r!ryr;rrr{rrHr#r#r$rss  zFirewallPolicy._portcCs:x4|jjD]&}|jsq |j|||}|j||q WdS)N)rrrr8r)r!ryr;rr{rrHr#r#r$rts zFirewallPolicy._protocolcCs<x6|jjD](}|jsq |j||||}|j||q WdS)N)rrrr9r)r!ryr;rrr{rrHr#r#r$rus zFirewallPolicy._source_portcCs8d}|jt||jj|}|j||}|j||dS)Nr)rrrr(r;r)r!ryr;r{rrrHr#r#r$rvs    zFirewallPolicy._masqueradec CsXtd|rd}nd}|r(|r(|jt||jj|} | j||||||} |j| | dS)Nrr)rrrrr(r<r) r!ryr;r{rrrrrrrHr#r#r$rqs    zFirewallPolicy._forward_portc Cs|jjj|}xl|jjD]^}|js&qd}|jrXx&dD]}||jkr6|j|s6d}Pq6W|r^q|j|||} |j|| qWdS)NFrrT)rr) rr1r2rrr%r4r=r) r!ryr;rr{r&rZ skip_backendrrHr#r#r$rps   zFirewallPolicy._icmp_blockcCsh|j|j}|dkrdS|j| r0|dkr0dSx2|jjD]$}|jsHq<|j||}|j||q|jdD]}|jjj|drfPqfW|jd$|jd%|Sd&g}|jjs|jd'x4|jdD]}|jjj|drPqW|jd(x>|jdD]}|jjj|drPqW|jd)|jd*|SdS)+z:Create a list of (table, chain) needed for policy dispatchr6r4r5r7rrOr*rKmanglerLrPrNrMZ interfacesN)rrO)r*rK)rSrK)rLrK)rrO)rLrK)rrP)rrN)r*rK)r*rM)rSrK)rLrK)rrN)r*rK)rSrK)rLrK)r*rM)rrN)r*rM)rLrK)r*rK)rSrK)rrN)rLrK)r*rM)r*rK)rSrK)r r<rnftables_enabledr0r:r8)r!r;rMtcr:r#r#r$rlsj                 z4FirewallPolicy._get_table_chains_for_policy_dispatchcCsr|j|}d|jdkr4dg}|jjs0|jd|Sd|jdkrLdddgSd|jd krbddgStd|SdS)z8Create a list of (table, chain) needed for zone dispatchr5r7rrOrLrKr6 FORWARD_INr*rSr4 FORWARD_OUTrMzInvalid policy: %sN)rrO)rLrK)rrV)r*rK)rSrK)rrW)r*rM)r r<rrTr0r)r!r;rMrUr#r#r$rms  z2FirewallPolicy._get_table_chains_for_zone_dispatchFcCs|jjj|}|jr|j}n||}d|jdkrl|dkrBd|S|dkrRd|S|jsh|dkrhd|SnJd|jd kr|js|dkrd |Sn"d |jdkr|dkr|jrd |Sd |Sn0|dkr|rd|Sd|Sn|dkrd|Snd |jd krh|dkr*|jr d|Sd |Sn<|dkrL|rBd|Sd|Sn|dkr|jsd|SnN|js|dkrd |S|dkr|rd|Sd|Sn|dkrd|Std|||fS)Nr5r7rZIN_rLZPRE_rSr*r4ZOUT_r6ZFWDI_ZFWD_ZPOST_ZFWDO_z.Can't convert policy to chain name: %s, %s, %s)rSr*)rSrL)rSrL)rSrL)rr;r.r/r<r)r!r;r|Z policy_prefixZisSNATrMsuffixr#r#r$policy_base_chain_namesb                z%FirewallPolicy.policy_base_chain_name)N)N)N)N)rNNT)N)rNNT)N)rNN)N)rNN)N)rNN)N)rNN)N)rNN)N)rNN)N)NN)NN)NNrNN)NNN)NN)rNN)N)NN)N)N)N)NN)F)__name__ __module__ __qualname__r%r'r)r*r-r3r=r.rNrQrLrdrerr8rrcrPrrrrrSrrrrrrrrTrrrrrrrrrwr^rrrrrrrrWrrrrrrrrrrXrrrrrrrr\rrrrrrr]rrrrrrr_rrrrrrrVrrrrrrrrUr rr r rr rrrrrrrnrrr#r"rrrrrrsrtrurvrqrprrJrQrRrorlrmrYr#r#r#r$rs$  '  ?  . , # , # :     ' (   ' ( '   +     ) )  @ @    ( P r)'rhr.Zfirewall.core.loggerrZfirewall.functionsrrrrrrr r r r rr rrrrrrrrrrZfirewall.core.fw_transactionrZfirewallrZfirewall.errorsrZfirewall.fw_typesrZfirewall.core.baserobjectrr#r#r#r$s 04     PKpge[$__pycache__/fw_helper.cpython-36.pycnu[3 g)@s6dZdgZddlmZddlmZGdddeZdS)zhelper backendFirewallHelper)errors) FirewallErrorc@s\eZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ dS)rcCs||_i|_dS)N)Z_fw_helpers)selffwr/usr/lib/python3.6/fw_helper.py__init__szFirewallHelper.__init__cCsd|j|jfS)Nz%s(%r)) __class__r)rrrr __repr__"szFirewallHelper.__repr__cCs|jjdS)N)rclear)rrrr cleanup'szFirewallHelper.cleanupcCs||jkrttj|dS)N) get_helpersrrINVALID_HELPER)rnamerrr check_helper*s zFirewallHelper.check_helpercCs ||jkS)N)r)rrrrr query_helper.szFirewallHelper.query_helpercCst|jjS)N)sortedrkeys)rrrr r1szFirewallHelper.get_helperscCst|jdkS)Nr)lenr)rrrr has_helpers4szFirewallHelper.has_helperscCs|j||j|S)N)rr)rrrrr get_helper7s zFirewallHelper.get_helpercCs||j|j<dS)N)rr)robjrrr add_helper;szFirewallHelper.add_helpercCs"||jkrttj||j|=dS)N)rrrr)rrrrr remove_helper>s  zFirewallHelper.remove_helperN) __name__ __module__ __qualname__r r rrrrrrrrrrrr rsN)__doc____all__ZfirewallrZfirewall.errorsrobjectrrrrr s  PKpge[&__pycache__/fw_nm.cpython-36.opt-1.pycnu[3 g@s dZddddddddgZd d lZd d lmZyejd d Wnek rTdZYn8Xyd dlmZdZWn e eej fk rdZYnXd a d dl m Z d dlmZd dlmZd d lZddZddZddZddZddZddZddZddZdd Zd!dZd"dZd#dZd S)$z(Functions for NetworkManager interactioncheck_nm_importednm_is_importednm_get_zone_of_connectionnm_set_zone_of_connectionnm_get_connectionsnm_get_connection_of_interfacenm_get_bus_namenm_get_dbus_interfaceN)GLibNMz1.0F)r T)errors) FirewallError)logcCststtjddS)zNCheck function to raise a MISSING_IMPORT error if the import of NM failed zgi.repository.NM = 1.0N) _nm_importedr r ZMISSING_IMPORTrr/usr/lib/python3.6/fw_nm.pyr0scCstS)znReturns true if NM has been properly imported @return True if import was successful, False otherwirse )rrrrrr6scCststjjdatS)zReturns the NM client object or None if the import of NM failed @return NM.Client instance if import was successful, None otherwise N) _nm_clientr ZClientnewrrrr nm_get_client<s rc Csttj|}|dkrdS|j}|dkr2dSy |jtjjtjjB@rPdSWn t k rr|j rndSYnX|j }|dkrd}|S)zGet zone of connection from NM @param connection name @return zone string setting of connection, empty string if not set, None if connection is unknown N) rrget_connection_by_uuidget_setting_connection get_flagsr SettingsConnectionFlags NM_GENERATED NM_VOLATILEAttributeError get_unsavedZget_zone) connectioncon setting_conzonerrrrEs$    cCsVttj|}|dkrdS|j}|dkr2dS|dkr>d}|jd||jddS)zSet the zone for a connection @param zone name @param connection name @return True if zone was set, else False NFrr!T)rrrrZ set_propertyZcommit_changes)r!rrr rrrrcs  c Cs~|j|jttj}xX|D]P}|jr4q&|j}|j}|j}|||<x |D]}|j}|rZ|||<qZWq&WdS)znGet active connections from NM @param connections return dict @param connections_name return dict N) clearrrget_active_connectionsget_vpnZget_idget_uuid get_devices get_ip_iface) Z connectionsZconnections_nameZactive_connections active_connameZuuidZdevicesdevip_ifacerrrrxs   c Cstg}xtjD]|}|jr$qy&|j}|jtjjtjj B@rHwWnt k rh|j rdwYnXx&|j D]}|j }|rt|j|qtWqW|S)zGGet active interfaces from NM @returns list of interface names )rrr#r$get_connectionrr rrrrrr&r'append)Zactive_interfacesr(rr*r+rrrnm_get_interfacess$  r.cCs6g}x,tD]"}t|}|t|kr |j|q W|S)N)r.rrr-)r!Z interfaces interfaceZconnrrrnm_get_interfaces_in_zones   r0cCs<tx0tjD]"}|j}|dkr(q||kr|SqWdS)zzGet device from NM which has the given IP interface @param interface name @returns NM.Device instance or None N)rrr&r')r/devicer+rrrnm_get_device_by_ip_ifacesr2c Csxtt|}|dkrdS|j}|dkr.dSy |j}|jtjj@rLdSWn tk rn|j rjdSYnX|j S)zGet connection from NM that is using the interface @param interface name @returns connection that is using interface or None N) rr2Zget_active_connectionr,rr rrrrr%)r/r1r(rrrrrs c CsRtsdSy&tj}|jtjtj}|j}~~|Stk rLt j dYnXdS)Nz(Failed to get bus name of NetworkManager) rdbusZ SystemBusZ get_objectr DBUS_INTERFACEZ DBUS_PATHZbus_name ExceptionrZdebug2)Zbusobjr)rrrrscCstsdStjS)Nr)rr r4rrrrrs)__doc____all__ZgiZ gi.repositoryr Zrequire_version ValueErrorrr ImportErrorErrorrZfirewallr Zfirewall.errorsr Zfirewall.core.loggerrr3rrrrrrr.r0r2rrrrrrrs@           PKpge[ Dm &__pycache__/fw_icmptype.cpython-36.pycnu[3 g @s>dgZddlmZddlmZddlmZGdddeZdS)FirewallIcmpType)log)errors) FirewallErrorc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)rcCs||_i|_dS)N)_fw _icmptypes)selffwr !/usr/lib/python3.6/fw_icmptype.py__init__szFirewallIcmpType.__init__cCsd|j|jfS)Nz%s(%r)) __class__r)rr r r __repr__!szFirewallIcmpType.__repr__cCs|jjdS)N)rclear)rr r r cleanup$szFirewallIcmpType.cleanupcCst|jjS)N)sortedrkeys)rr r r get_icmptypes)szFirewallIcmpType.get_icmptypescCs||jkrttj|dS)N)rrrZINVALID_ICMPTYPE)ricmptyper r r check_icmptype,s zFirewallIcmpType.check_icmptypecCs|j||j|S)N)rr)rrr r r get_icmptype0s zFirewallIcmpType.get_icmptypecCs|j}t|dkrddg}x|D]z}|dkrL|jj rB|jj rBq |jj}n,|dkrt|jj rj|jj rjq |jj}ng}|jj |kr t j d|j|fq W||j |j<dS)NrZipv4Zipv6z5ICMP type '%s' is not supported by the kernel for %s.) Z destinationlenrZip4tables_enabledZnftables_enabledZipv4_supported_icmp_typesZip6tables_enabledZipv6_supported_icmp_typesnamelowerrZinfo1r)robjZ orig_ipvsZipvZsupported_icmpsr r r add_icmptype4s     zFirewallIcmpType.add_icmptypecCs|j||j|=dS)N)rr)rrr r r remove_icmptypeGs z FirewallIcmpType.remove_icmptypeN) __name__ __module__ __qualname__r rrrrrrrr r r r rsN) __all__Zfirewall.core.loggerrZfirewallrZfirewall.errorsrobjectrr r r r s   PKpge[|}RR"__pycache__/fw_zone.cpython-36.pycnu[3 gy@sddlZddlZddlmZmZmZddlmZddlm Z ddl m Z ddl m Z mZmZmZmZmZmZmZmZddlmZmZmZddlmZdd lmZdd lmZGd d d e Z!dS) N) SHORTCUTSDEFAULT_ZONE_TARGETSOURCE_IPSET_TYPES)FirewallTransaction)Policy)log) Rich_Service Rich_Port Rich_ProtocolRich_SourcePortRich_ForwardPortRich_IcmpBlock Rich_IcmpTypeRich_Masquerade Rich_Mark) checkIPnMask checkIP6nMask check_mac)errors) FirewallError)LastUpdatedOrderedDictc@sNeZdZdZddZddZddZdd Zd d Zd d Z ddZ ddZ ddZ ddZ ddZddZddZddZddd Zd!d"Zd#d$Zd%d&Zdd'd(Zd)d*Zd+d,Zd-d.Zdd/d0Zdd1d2Zd3d4Zd5d6Zd7d8Zd9d:Zd;d<Z d=d>Z!dd@dAZ"dBdCZ#ddDdEZ$ddFdGZ%ddHdIZ&dJdKZ'dLdMZ(dNdOZ)ddQdRZ*ddSdTZ+ddUdVZ,dWdXZ-ddYdZZ.dd[d\Z/d]d^Z0d_d`Z1dadbZ2ddcddZ3dedfZ4dgdhZ5didjZ6dkdlZ7dmdnZ8dodpZ9ddqdrZ:dsdtZ;dudvZd{d|Z?d}d~Z@ddZAdddZBddZCddZDddZEddZFdddZGddZHddZIddZJdddZKddZLddZMddZNdddZOddZPddZQdddZRdddZSdddZTddZUdddZVddZWddZXddZYdddZZddZ[ddZ\ddZ]ddZ^ddZ_dddZ`ddZaddd„ZbddĄZcddƄZddS) FirewallZonercCs||_i|_i|_dS)N)_fw_zones_zone_policies)selffwr/usr/lib/python3.6/fw_zone.py__init__&szFirewallZone.__init__cCsd|j|jfS)Nz%s(%r)) __class__r)rrrr__repr__+szFirewallZone.__repr__cCs|jj|jjdS)N)rclearr)rrrrcleanup.s zFirewallZone.cleanupcCs t|jS)N)rr)rrrrnew_transaction2szFirewallZone.new_transactioncCsdj||dS)Nzzone_{fromZone}_{toZone})fromZonetoZone)format)rr%r&rrrpolicy_name_from_zones5sz#FirewallZone.policy_name_from_zonescCst|jjS)N)sortedrkeys)rrrr get_zones:szFirewallZone.get_zonescCs8g}x.|jD]"}|j|s&|j|r|j|qW|S)N)r+list_interfaces list_sourcesappend)rZ active_zoneszonerrrget_active_zones=s zFirewallZone.get_active_zonescCs6|j|}x&|jD]}||j|jdkr|SqWdS)N interfaces)_FirewallZone__interface_idrsettings)r interface interface_idr/rrrget_zone_of_interfaceDs   z"FirewallZone.get_zone_of_interfacecCs6|j|}x&|jD]}||j|jdkr|SqWdS)Nsources)_FirewallZone__source_idrr3)rsource source_idr/rrrget_zone_of_sourceLs   zFirewallZone.get_zone_of_sourcecCs|jj|}|j|S)N)r check_zoner)rr/zrrrget_zoneTs zFirewallZone.get_zonecCsBt}|j|_|j|||_|j|_|j|_|g|_|g|_xd D]}||jkr~|d kr~|d kr~t ||t j t ||qD|d kr||jkr|d krt ||t j t ||qD||jko|d ko|dkrt ||t j t ||qD|dkrDg|_ xB|j D]8}|j||}||j|j|kr|j jt j |qWqDW|S)Nservicesports masquerade forward_ports source_ports icmp_blocksrules protocolsHOSTANY)r?r@rArBrCrDrErF)r?r@rCrDrF)rA)rDrB)rE)rnameZderived_from_zoner(ZONE_POLICY_PRIORITYZprioritytargetZ ingress_zonesZ egress_zonessetattrcopydeepcopygetattrrE_rich_rule_to_policiesr.)rz_objr%r&p_objZsettingruleZcurrent_policyrrrpolicy_obj_from_zone_objXs6    z%FirewallZone.policy_obj_from_zone_objcCsddd D|_||j|j<g|j|j<xX|jdfd|jf|jdfgD]8\}}|j|||}|jjj||j|jj|jqFW|j |jdS) NcSsi|] }t|qSr)r).0xrrr sz)FirewallZone.add_zone..r1r7icmp_block_inversionforwardrGrH)r1r7rXrY) r3rrIrrTrpolicyZ add_policyr.copy_permanent_to_runtime)robjr%r&rRrrradd_zone~s   zFirewallZone.add_zonecCsn|j|}x|jD]}|j||ddqWx|jD]}|j||ddq2W|jrZ|j||jrj|j|dS)NF) allow_apply) rr1 add_interfacer7 add_sourcerY add_forwardrXadd_icmp_block_inversion)rr/r\argrrrr[s    z&FirewallZone.copy_permanent_to_runtimecCs8|j|}|jr|j||jj|j|=|j|=dS)N)rappliedunapply_zone_settingsr3r"r)rr/r\rrr remove_zones    zFirewallZone.remove_zoneNcCsVxP|jD]D}|j|}t|jdks4t|jdkr tjd||j||dq WdS)NrzApplying zone '%s')use_transaction)r+rlenr1r7rdebug1apply_zone_settings)rrgr/rQrrr apply_zoness   zFirewallZone.apply_zonescCs|j|}||_dS)N)rrd)rr/rdr\rrrset_zone_applieds zFirewallZone.set_zone_appliedcCsd|kr dS|jd}t|dkr&dSd}x tD]}|dt|kr0|}q0W|dk r|d|jkrhdSt|dkst|dkr|dd kr|d|fSdS) N_rprerdenyallowpost)rqrrrrsrt)splitrhrr+)rchainZsplits_chainrVrrrzone_from_chains      zFirewallZone.zone_from_chaincCst|j|}|dkrdS|\}}|d kr0|}d}n4|d krB|}d}n"|d krTd}|}nttjd||j|||fS) N PREROUTING FORWARD_INrHINPUTrG POSTROUTING FORWARD_OUTz&chain '%s' can't be mapped to a policy)ryrz)r{)r|r})rxrrZ INVALID_CHAINr()rrvrVr/rwr%r&rrrpolicy_from_chains zFirewallZone.policy_from_chainc Csj|dkrf|j|}|dk rf|j|\}}|dkr:|j}n|}|jjj|d||||dkrf|jddS)Nipv4ipv6T)rr)r~r$rrZZgen_chain_rulesexecute) ripvtablervrgrVrZrw transactionrrrcreate_zone_base_by_chains  z&FirewallZone.create_zone_base_by_chaincCstj||d}|S)N)Zdatesendertimeout)time)rrrretrrrZ__gen_settingsszFirewallZone.__gen_settingscCs |j|jS)N)r>r3)rr/rrr get_settingsszFirewallZone.get_settingscCs|j|}x|D]z}xt||D]h}|dkr<|j||||q|dkr`|j|||d|d|q|dkrlqq|dkrvqtjd|||qWqW|r|j|||dS)Nr1r7rrorXrYz3Zone '%s': Unknown setting '%s:%s', unable to apply)r _interface_sourcerZwarning_icmp_block_inversion)renabler/rr3keyargsrrr_zone_settingss  zFirewallZone._zone_settingscCs|jj|}|j|}|jr dSd|_|dkr8|j}n|}x2|j|D]$}tjd|||jjj ||dqHW|j d|||dkr|j ddS)NTz+Applying policy (%s) derived from zone '%s')rg) rr<rrdr$rrrirZapply_policy_settingsrr)rr/rg_zoner\rrZrrrrjs   z FirewallZone.apply_zone_settingscCs|jj|}|j|}|js dS|dkr2|j}n|}x$|j|D]}|jjj||dqBW|jd|||dkr||j ddS)N)rgFT) rr<rrdr$rrZunapply_policy_settingsrr)rr/rgrr\rrZrrrre,s   z"FirewallZone.unapply_zone_settingscCs~|j|}|j|}g}x\tdD]P}|j|d|krZ|jtjt||j|dq"|j||j|dq"Wt|S)zH :return: exported config updated with runtime settings r) r>get_config_with_settings_dictrangeZIMPORT_EXPORT_STRUCTUREr.rMrNrOtuple)rr/r\Z conf_dictZ conf_listirrrget_config_with_settings?s  "z%FirewallZone.get_config_with_settingsc Cs|j|j}|dtkr"d|d<|j||j||j||j||j||j||j ||j ||j ||j ||j ||j|d }|jj||S)zH :return: exported config updated with runtime settings rKdefault) r?r@rDrArBr1r7 rules_strrFrCrXrY)r>Zexport_config_dictr list_services list_portslist_icmp_blocksquery_masqueradelist_forward_portsr,r- list_ruleslist_protocolslist_source_portsquery_icmp_block_inversion query_forwardrZ'combine_runtime_with_permanent_settings)rr/Z permanentZruntimerrrrOs  z*FirewallZone.get_config_with_settings_dictc sddlmdfdd }fdd}jjfjjfjjfjj fj j fj j fjjf||fjjfjjfjjfjjfd }j|}jj||\}} xv| D]n} t| | tr$xX| | D]:} t| tr || d|f| q|| d|| qWq|| d|qWx|D]} t|| trx|| D]l} | dkr|| d|| |d nDt| tr|| d|f| d|d n|| d|| d|d q\Wn6| dkr|| d||d n|| d|d|d q>WdS)Nr) Rich_Rulecsj||dd|ddS)N)rule_strr)rr)add_rule)r/rrr)rrrradd_rule_wrapperhszDFirewallZone.set_config_with_settings_dict..add_rule_wrappercsj||ddS)N)r) remove_rule)r/r)rrrrremove_rule_wrapperjszGFirewallZone.set_config_with_settings_dict..remove_rule_wrapper) r?r@rDrArBr1r7rrFrCrXrYror1r7)r)rrrX)rN)r1r7)rX)firewall.core.richr add_serviceremove_serviceadd_port remove_portadd_icmp_blockremove_icmp_blockadd_masqueraderemove_masqueradeadd_forward_portremove_forward_portr_remove_interfacer` remove_source add_protocolremove_protocoladd_source_portremove_source_portrbremove_icmp_block_inversionraremove_forwardrrZget_added_and_removed_settings isinstancelistr) rr/r3rrrZ setting_to_fnZ old_settingsZ add_settingsZremove_settingsrrr)rrrset_config_with_settings_dictesF                    z*FirewallZone.set_config_with_settings_dictcCs|jj|dS)N)rcheck_interface)rr4rrrrszFirewallZone.check_interfacecCs\|jj|}|j|}|j|}||jdkrX|jd|}d|krX|ddk rX|dSdS)Nr1r)rr<rr2r3)rr/r4r_objr5r3rrrinterface_get_senders   z!FirewallZone.interface_get_sendercCs|j||S)N)r)rr4rrrZ__interface_ids zFirewallZone.__interface_idTc Cs|jj|jj|}|j|}|j|}||jdkrLttjd||f|j |dk rjttj d|t j d||f|dkr|j } n|} |j r|r|j|| d| j|j|d|r|jd||| |j||||| j|j|||dkr| jd|S)Nr1z'%s' already bound to '%s'z'%s' already bound to a zonez&Setting zone of interface '%s' to '%s')rgFT)r check_panicr<rr2r3rrZONE_ALREADY_SETr6 ZONE_CONFLICTrrir$rdrjadd_failrlr!_FirewallZone__register_interface#_FirewallZone__unregister_interfacer) rr/r4rrgr^rrr5rrrrr_s8            zFirewallZone.add_interfacecCs6|jd||jd|<| p"|dk|jd|d<dS)Nrr1 __default__)_FirewallZone__gen_settingsr3)rrr5r/rrrrZ__register_interfacesz!FirewallZone.__register_interfacecCsR|jj|j|}|jj|}||kr,|S|dk r@|j|||j|||}|S)N)rrr6r<rr_)rr/r4r _old_zone _new_zonerrrrchange_zone_of_interfaces    z%FirewallZone.change_zone_of_interfacecCsz|jj|dkr|j}n|}|j|||jd|d|dd|dk rd|dkrd|jd|d|dd|dkrv|jddS)NT+)r.rF)rrr$rjrr)rZold_zoneZnew_zonergrrrrchange_default_zones   z FirewallZone.change_default_zonec Cs|jj|j|}|dkr,ttjd||dkr8|n |jj|}||krbttjd|||f|dkrt|j}n|}|j |}|j |}|j |j |||j d||||dkr|jd|S)Nz'%s' is not in any zonerz"remove_interface(%s, %s): zoi='%s'FT)rrr6rrZUNKNOWN_INTERFACEr<rr$rr2add_postrrr) rr/r4rgZzoirrrr5rrrrs(       zFirewallZone.remove_interfacecCs||jdkr|jd|=dS)Nr1)r3)rrr5rrrZ__unregister_interfacesz#FirewallZone.__unregister_interfacecCs|j||j|dkS)Nr1)r2r)rr/r4rrrquery_interfaceszFirewallZone.query_interfacecCs|j|djS)Nr1)rr*)rr/rrrr,"szFirewallZone.list_interfacesFcCsxt|r dSt|rdSt|r$dS|jdrh|j|dd|rV|j|dd|j|ddSttj |dS)Nrrrzipset:) rrr startswith_check_ipset_type_for_source_check_ipset_applied _ipset_familyrrZ INVALID_ADDR)rr9rdrrr check_source's zFirewallZone.check_sourcecCs|j||d}||fS)N)rd)r)rr9rdrrrrZ __source_id6szFirewallZone.__source_idc Cs|jj|jj|}|j|}t|r0|j}|j||d}||jdkr`tt j d||f|j |dk r~tt j d||dkr|j } n|} |j r|r|j|| d| j|j|d|r|jd||d|d | |j||||| j|j|||dkr| jd|S) N)rdr7z'%s' already bound to '%s'z'%s' already bound to a zone)rgFTrro)rrr<rrupperr8r3rrrr;rr$rdrjrrlr_FirewallZone__register_source _FirewallZone__unregister_sourcer) rr/r9rrgr^rrr:rrrrr`:s4        zFirewallZone.add_sourcecCs6|jd||jd|<| p"|dk|jd|d<dS)Nrr7rr)rr3)rrr:r/rrrrZ__register_sourceaszFirewallZone.__register_sourcecCsb|jj|j|}|jj|}||kr,|St|r<|j}|dk rP|j|||j|||}|S)N)rrr;r<rrrr`)rr/r9rrrrrrrchange_zone_of_sourcegs    z"FirewallZone.change_zone_of_sourcec Cs|jjt|r|j}|j|}|dkrsz-FirewallZone.list_sources..r7)rr*)rr/rrrr-szFirewallZone.list_sourcesc sxjjD]}|jsq xPj|D]B}x<jjj|D]*\}} |j|||||| |} |j|| q8Wq$Wj|d}j |dr |d kr |j |||d|d} |j|| q WxΈjjj D]}|jjj |kr|jjj |krq|jjjkrdjjj|jrd| rsz)FirewallZone._interface..cs|jjjkojjj|S)N)rrZrr)r)rrrrs)rr)renabled_backendspolicies_supportedrrZ#_get_table_chains_for_zone_dispatchZ!build_zone_source_interface_rules add_rulesr(rbuild_zone_forward_rules"get_policies_not_derived_from_zonelist_ingress_zoneslist_egress_zonesr get_policyrdrhr,r_ingress_egress_zonesr) rrr/r4rr.backendrZrrvrEr)rrrs2 $zFirewallZone._interfacecCs$|j|dkrdS|jjj|ddS)Nzhash:macF)rd) _ipset_typeripsetZ get_family)rrIrrrrszFirewallZone._ipset_familycCs|jjj|ddS)NF)rd)rrZget_type)rrIrrrrszFirewallZone._ipset_typecCsdj|g|jjj|S)N,)joinrrZ get_dimension)rrIflagrrr_ipset_match_flagsszFirewallZone._ipset_match_flagscCs|jjj|S)N)rrZ check_applied)rrIrrrrsz!FirewallZone._check_ipset_appliedcCs*|j|}|tkr&ttjd||fdS)Nz.ipset '%s' with type '%s' not usable as source)rrrrZ INVALID_IPSET)rrIZ_typerrrrs  z)FirewallZone._check_ipset_type_for_sourcec sx|rjj|gnjjD]}|js*qxNj|D]@}x:jjj|D](\}} |j|||||| } |j|| qJWq6Wj |d}j |dr|j |||d|d} |j|| qWxΈjjj D]}|jjj |kr|jjj|krq|jjjkrljjj|jrl| rDtj|dkrDjjj||dn&jjjd|||jfdd |q|r|jfd d |qWdS) NrHrYr)r9ro)rgFcs |jjjkojjjd|S)NT)rrZrr)r)rrrrsz&FirewallZone._source..cs|jjjkojjj|S)N)rrZrr)r)rrrr s)rget_backend_by_ipvrrrrZrZbuild_zone_source_address_rulesrr(rrrrrrrrdrhr-rrr) rrr/rr9rrrZrrvrEr)rrrs2"  $zFirewallZone._sourcecCs0|jj|}|j|d}|jjj|||||S)NrG)rr<r(rZr)rr/servicerrp_namerrrr s  zFirewallZone.add_servicecCs,|jj|}|j|d}|jjj|||S)NrG)rr<r(rZr)rr/rrrrrrs  zFirewallZone.remove_servicecCs(|jj|}|j|d}|jjj||S)NrG)rr<r(rZ query_service)rr/rrrrrrs  zFirewallZone.query_servicecCs&|jj|}|j|d}|jjj|S)NrG)rr<r(rZr)rr/rrrrrs  zFirewallZone.list_servicescCs2|jj|}|j|d}|jjj||||||S)NrG)rr<r(rZr)rr/portprotocolrrrrrrr#s  zFirewallZone.add_portcCs.|jj|}|j|d}|jjj||||S)NrG)rr<r(rZr)rr/rrrrrrr)s  zFirewallZone.remove_portcCs*|jj|}|j|d}|jjj|||S)NrG)rr<r(rZ query_port)rr/rrrrrrr/s  zFirewallZone.query_portcCs&|jj|}|j|d}|jjj|S)NrG)rr<r(rZr)rr/rrrrr4s  zFirewallZone.list_portscCs2|jj|}|j|d}|jjj||||||S)NrG)rr<r(rZr)rr/ source_portrrrrrrrr9s  zFirewallZone.add_source_portcCs.|jj|}|j|d}|jjj||||S)NrG)rr<r(rZr)rr/rrrrrrr?s  zFirewallZone.remove_source_portcCs*|jj|}|j|d}|jjj|||S)NrG)rr<r(rZquery_source_port)rr/rrrrrrrEs  zFirewallZone.query_source_portcCs&|jj|}|j|d}|jjj|S)NrG)rr<r(rZr)rr/rrrrrJs  zFirewallZone.list_source_portscCs|jj|}t|jtkr(|j|dgSt|jttt t gkrL|j|dgSt|jt t gkrv|j|d|j|dgSt|jt gkr|j|dgSt|jtgkr|jd|gS|jdkr|j|dgStdt|jdS)NrHrGz Rich rule type (%s) not handled.)rr<typeactionrr(elementrr r r r rr rr)rr/rSrrrrPOs    z#FirewallZone._rich_rule_to_policiescCs.x(|j||D]}|jjj||||qW|S)N)rPrrZr)rr/rSrrrrrrrbszFirewallZone.add_rulecCs*x$|j||D]}|jjj||qW|S)N)rPrrZr)rr/rSrrrrrgszFirewallZone.remove_rulecCs2d}x(|j||D]}|o(|jjj||}qW|S)NT)rPrrZ query_rule)rr/rSrrrrrrlszFirewallZone.query_rulecCs^|jj|}t}xB|j|d|j|d|jd|gD]}|jt|jjj|q6Wt|S)NrHrG)rr<setr(updaterZrr)rr/rrrrrrrs   zFirewallZone.list_rulescCs0|jj|}|j|d}|jjj|||||S)NrG)rr<r(rZr)rr/rrrrrrrr{s  zFirewallZone.add_protocolcCs,|jj|}|j|d}|jjj|||S)NrG)rr<r(rZr)rr/rrrrrrs  zFirewallZone.remove_protocolcCs(|jj|}|j|d}|jjj||S)NrG)rr<r(rZquery_protocol)rr/rrrrrr s  zFirewallZone.query_protocolcCs&|jj|}|j|d}|jjj|S)NrG)rr<r(rZr)rr/rrrrrs  zFirewallZone.list_protocolscCs.|jj|}|jd|}|jjj||||S)NrH)rr<r(rZr)rr/rrrrrrrs  zFirewallZone.add_masqueradecCs*|jj|}|jd|}|jjj||S)NrH)rr<r(rZr)rr/rrrrrs  zFirewallZone.remove_masqueradecCs&|jj|}|jd|}|jjj|S)NrH)rr<r(rZr)rr/rrrrrs  zFirewallZone.query_masqueradec Cs6|jj|}|j|d}|jjj||||||||S)NrH)rr<r(rZr) rr/rrtoporttoaddrrrrrrrrs   zFirewallZone.add_forward_portcCs2|jj|}|j|d}|jjj||||||S)NrH)rr<r(rZr)rr/rrr r rrrrrs  z FirewallZone.remove_forward_portcCs.|jj|}|j|d}|jjj|||||S)NrH)rr<r(rZquery_forward_port)rr/rrr r rrrrr s  zFirewallZone.query_forward_portcCs&|jj|}|j|d}|jjj|S)NrH)rr<r(rZr)rr/rrrrrs  zFirewallZone.list_forward_portscCsP|jj|}|j|d}|jjj|||||j|d}|jjj|||||S)NrGrH)rr<r(rZr)rr/icmprrrrrrrs    zFirewallZone.add_icmp_blockcCsH|jj|}|j|d}|jjj|||j|d}|jjj|||S)NrGrH)rr<r(rZr)rr/r rrrrrs    zFirewallZone.remove_icmp_blockcCsD|jj|}|j|d}|j|d}|jjj||oB|jjj||S)NrGrH)rr<r(rZquery_icmp_block)rr/r  p_name_host p_name_fwdrrrrs    zFirewallZone.query_icmp_blockcCsH|jj|}|j|d}|j|d}tt|jjj||jjj|S)NrGrH)rr<r(r)rrZr)rr/rrrrrrs    zFirewallZone.list_icmp_blockscCsH|jj|}|j|d}|jjj|||j|d}|jjj|||S)NrGrH)rr<r(rZrb)rr/rrrrrrbs    z%FirewallZone.add_icmp_block_inversioncCsL|jj|}|j|d}|jjj||||j|d}|jjj|||dS)NrGrH)rr<r(rZr)rrr/rrrrrrs    z"FirewallZone._icmp_block_inversioncCsD|jj|}|j|d}|jjj||j|d}|jjj||S)NrGrH)rr<r(rZr)rr/rrrrrs    z(FirewallZone.remove_icmp_block_inversioncCs@|jj|}|j|d}|j|d}|jjj|o>|jjj|S)NrGrH)rr<r(rZr)rr/rrrrrrs    z'FirewallZone.query_icmp_block_inversionc Cs|j|d}xT|j|jdD]@}x:|jjD],}|js:q.|j|||d|d}|j||q.WqWxj|j|jdD]V\}} xL|r|jj|gn|jjD],}|jsq|j|||d| d}|j||qWqtWdS)NrHr1r)r4r7)r9) r(rr3rrrrrr) rrr/rrr4rrErr9rrr_forwards "zFirewallZone._forwardcCsdS)NTr)rrrrZ __forward_idszFirewallZone.__forward_idc Cs|jj|}|jj||jj|j|}|j}||jdkrRttj d||dkrd|j }n|}|j r||j d|||j |||||j|j|||dkr|jd|S)NrYzforward already enabled in '%s'T)rr<Z check_timeoutrr_FirewallZone__forward_idr3rrZALREADY_ENABLEDr$rdr_FirewallZone__register_forwardr!_FirewallZone__unregister_forwardr) rr/rrrgrr forward_idrrrrras$       zFirewallZone.add_forwardcCs|j|||jd|<dS)NrY)rr3)rrrrrrrrZ__register_forward.szFirewallZone.__register_forwardcCs|jj|}|jj|j|}|j}||jdkrFttjd||dkrX|j }n|}|j rp|j d|||j |j |||dkr|jd|S)NrYzforward not enabled in '%s'FT)rr<rrrr3rrZ NOT_ENABLEDr$rdrrrr)rr/rgrrrrrrrr2s       zFirewallZone.remove_forwardcCs||jdkr|jd|=dS)NrY)r3)rrrrrrZ__unregister_forwardKsz!FirewallZone.__unregister_forwardcCs|j|j|dkS)NrY)rr)rr/rrrrOszFirewallZone.query_forward)N)N)N)N)NNT)N)N)N)F)F)NNT)N)N)F)rN)rN)rN)rN)rN)rN)NNrN)NN)NN)rN)N)rNN)N)e__name__ __module__ __qualname__rJrr!r#r$r(r+r0r6r;r>rTr]r[rfrkrlrxr~rrrrrjrerrrrrr2r_rrrrrrr,rr8r`rrrrrr-rrrrrrrrrrrrrrrrrrrrPrrrrrrr rrrrrrr rrrrrrbrrrrrrarrrrrrrrr#s&     8  (      &   ,(               r)"rrMZfirewall.core.baserrrZfirewall.core.fw_transactionrZfirewall.core.io.policyrZfirewall.core.loggerrrrr r r r r rrrZfirewall.functionsrrrZfirewallrZfirewall.errorsrZfirewall.fw_typesrobjectrrrrrs   ,   PKpge[K+__pycache__/fw_service.cpython-36.opt-1.pycnu[3 gg@s2dgZddlmZddlmZGdddeZdS)FirewallService)errors) FirewallErrorc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)rcCs||_i|_dS)N)Z_fw _services)selffwr /usr/lib/python3.6/fw_service.py__init__szFirewallService.__init__cCsd|j|jfS)Nz%s(%r)) __class__r)rrrr __repr__ szFirewallService.__repr__cCs|jjdS)N)rclear)rrrr cleanup#szFirewallService.cleanupcCst|jjS)N)sortedrkeys)rrrr get_services(szFirewallService.get_servicescCs||jkrttj|dS)N)rrrZINVALID_SERVICE)rservicerrr check_service+s zFirewallService.check_servicecCs|j||j|S)N)rr)rrrrr get_service/s zFirewallService.get_servicecCs||j|j<dS)N)rname)robjrrr add_service3szFirewallService.add_servicecCs|j||j|=dS)N)rr)rrrrr remove_service6s zFirewallService.remove_serviceN) __name__ __module__ __qualname__r r rrrrrrrrrr rsN)__all__ZfirewallrZfirewall.errorsrobjectrrrrr s  PKpge[ __pycache__/fw_nm.cpython-36.pycnu[3 g@s dZddddddddgZd d lZd d lmZyejd d Wnek rTdZYn8Xyd dlmZdZWn e eej fk rdZYnXd a d dl m Z d dlmZd dlmZd d lZddZddZddZddZddZddZddZddZdd Zd!dZd"dZd#dZd S)$z(Functions for NetworkManager interactioncheck_nm_importednm_is_importednm_get_zone_of_connectionnm_set_zone_of_connectionnm_get_connectionsnm_get_connection_of_interfacenm_get_bus_namenm_get_dbus_interfaceN)GLibNMz1.0F)r T)errors) FirewallError)logcCststtjddS)zNCheck function to raise a MISSING_IMPORT error if the import of NM failed zgi.repository.NM = 1.0N) _nm_importedr r ZMISSING_IMPORTrr/usr/lib/python3.6/fw_nm.pyr0scCstS)znReturns true if NM has been properly imported @return True if import was successful, False otherwirse )rrrrrr6scCststjjdatS)zReturns the NM client object or None if the import of NM failed @return NM.Client instance if import was successful, None otherwise N) _nm_clientr ZClientnewrrrr nm_get_client<s rc Csttj|}|dkrdS|j}|dkr2dSy |jtjjtjjB@rPdSWn t k rr|j rndSYnX|j }|dkrd}|S)zGet zone of connection from NM @param connection name @return zone string setting of connection, empty string if not set, None if connection is unknown N) rrget_connection_by_uuidget_setting_connection get_flagsr SettingsConnectionFlags NM_GENERATED NM_VOLATILEAttributeError get_unsavedZget_zone) connectioncon setting_conzonerrrrEs$    cCsVttj|}|dkrdS|j}|dkr2dS|dkr>d}|jd||jddS)zSet the zone for a connection @param zone name @param connection name @return True if zone was set, else False NFrr!T)rrrrZ set_propertyZcommit_changes)r!rrr rrrrcs  c Cs~|j|jttj}xX|D]P}|jr4q&|j}|j}|j}|||<x |D]}|j}|rZ|||<qZWq&WdS)znGet active connections from NM @param connections return dict @param connections_name return dict N) clearrrget_active_connectionsget_vpnZget_idget_uuid get_devices get_ip_iface) Z connectionsZconnections_nameZactive_connections active_connameZuuidZdevicesdevip_ifacerrrrxs   c Cstg}xtjD]|}|jr$qy&|j}|jtjjtjj B@rHwWnt k rh|j rdwYnXx&|j D]}|j }|rt|j|qtWqW|S)zGGet active interfaces from NM @returns list of interface names )rrr#r$get_connectionrr rrrrrr&r'append)Zactive_interfacesr(rr*r+rrrnm_get_interfacess$  r.cCs6g}x,tD]"}t|}|t|kr |j|q W|S)N)r.rrr-)r!Z interfaces interfaceZconnrrrnm_get_interfaces_in_zones   r0cCs<tx0tjD]"}|j}|dkr(q||kr|SqWdS)zzGet device from NM which has the given IP interface @param interface name @returns NM.Device instance or None N)rrr&r')r/devicer+rrrnm_get_device_by_ip_ifacesr2c Csxtt|}|dkrdS|j}|dkr.dSy |j}|jtjj@rLdSWn tk rn|j rjdSYnX|j S)zGet connection from NM that is using the interface @param interface name @returns connection that is using interface or None N) rr2Zget_active_connectionr,rr rrrrr%)r/r1r(rrrrrs c CsRtsdSy&tj}|jtjtj}|j}~~|Stk rLt j dYnXdS)Nz(Failed to get bus name of NetworkManager) rdbusZ SystemBusZ get_objectr DBUS_INTERFACEZ DBUS_PATHZbus_name ExceptionrZdebug2)Zbusobjr)rrrrscCstsdStjS)Nr)rr r4rrrrrs)__doc____all__ZgiZ gi.repositoryr Zrequire_version ValueErrorrr ImportErrorErrorrZfirewallr Zfirewall.errorsr Zfirewall.core.loggerrr3rrrrrrr.r0r2rrrrrrrs@           PKpge[8&#__pycache__/nftables.cpython-36.pycnu[3 g%@slddlmZddlZddlZddlZddlmZddlmZm Z m Z m Z m Z ddl mZmZmZmZmZmZmZddlmZmZmZmZmZmZmZddlmZdZed d Z d Z!d Z"id ddCe"fiddDe"fdde"fddde"fdde"fdde"fdde"fddZ#dEddZ$e$ddde$dde$dde$dde$ddde$ddd e$ddd e$dd!d"e$ddd#e$ddd"e$dd$d"e$ddd%e$dd!de$ddd&e$ddde$dd$e$ddd'e$ddd(e$ddd)e$dd!e$dd$d"e$dd*e$dd+e$dd,e$ddd-e$dd.e$dd/e$dd0e$dd!d'e$ddd1e$dd!d)e$ddd2e$dd.d"e$dd.dd3"e$d4dd'e$d4d$de$d4dd)e$d4dd"e$d4de$d4de$d4de$d4dd-e$d4d5e$d4d6e$d4d7e$d4d8e$d4d9e$d4d:e$d4dde$d4d;e$d4d$e$d4dde$d4d<e$d4dd&e$d4d=e$d4d>e$d4d.e$d4d.d"e$d4d.de$d4d$d"e$d4d$d)d?d@Z%GdAdBdBe&Z'dS)F)absolute_importN)log) check_mac getPortRange normalizeIP6check_single_address check_address) FirewallError UNKNOWN_ERROR INVALID_RULEINVALID_ICMPTYPE INVALID_TYPE INVALID_ENTRY INVALID_PORT) Rich_Accept Rich_Reject Rich_Drop Rich_MarkRich_MasqueradeRich_ForwardPortRich_IcmpBlock)NftablesZ firewalld_Z policy_dropZpolicy_ PREROUTING preroutingdZ postrouting)r POSTROUTINGinputforwardoutput)rINPUTFORWARDOUTPUT)rawmanglenatfiltercCsHdd|ddid|dig}|dk rD|jdd|ddid|di|S)Nmatchpayloadtype)protocolfieldz==)leftoprightcode)append)r,r+r1 fragmentsr4/usr/lib/python3.6/nftables.py_icmp_types_fragmentsSs  r6icmpzdestination-unreachable z echo-replyz echo-requestredirectzparameter-problemzrouter-advertisementzrouter-solicitationz source-quenchz time-exceededztimestamp-replyztimestamp-request )"zcommunication-prohibitedzdestination-unreachablez echo-replyz echo-requestzfragmentation-neededzhost-precedence-violationzhost-prohibitedz host-redirectz host-unknownzhost-unreachablez ip-header-badznetwork-prohibitedznetwork-redirectznetwork-unknownznetwork-unreachablezparameter-problemzport-unreachablezprecedence-cutoffzprotocol-unreachabler;zrequired-option-missingzrouter-advertisementzrouter-solicitationz source-quenchzsource-route-failedz time-exceededztimestamp-replyztimestamp-requestztos-host-redirectztos-host-unreachableztos-network-redirectztos-network-unreachablezttl-zero-during-reassemblyzttl-zero-during-transiticmpv6zmld-listener-donezmld-listener-queryzmld-listener-reportzmld2-listener-reportznd-neighbor-advertznd-neighbor-solicitzpacket-too-bigz nd-redirectznd-router-advertznd-router-solicit)zaddress-unreachablez bad-headerz beyond-scopezcommunication-prohibitedzdestination-unreachablez echo-replyz echo-requestz failed-policyzmld-listener-donezmld-listener-queryzmld-listener-reportzmld2-listener-reportzneighbour-advertisementzneighbour-solicitationzno-routezpacket-too-bigzparameter-problemzport-unreachabler;z reject-routezrouter-advertisementzrouter-solicitationz time-exceededzttl-zero-during-reassemblyzttl-zero-during-transitzunknown-header-typezunknown-option)ipv4ipv6c@s`eZdZdZdZddZddZddZdd Zd d Z d d Z ddZ dddZ ddZ ddZddZddZdddZddZdd d!Zd"d#Zdd%d&Zdd(d)Zdd*d+Zdd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z!d@dAZ"dBdCZ#dDdEZ$dFdGZ%dHdIZ&ddJdKZ'dLdMZ(dNdOZ)dPdQZ*dRdSZ+ddTdUZ,ddVdWZ-ddXdYZ.dZd[Z/dd\d]Z0dd^d_Z1dd`daZ2ddbdcZ3ddddeZ4dfdgZ5ddhdiZ6djdkZ7ddldmZ8dndoZ9dpdqZ:drdsZ;dtduZdzd{Z?dd|d}Z@d~dZAddZBddZCddZDddZEddZFddZGdddZHdS)nftablesTcCsb||_d|_g|_i|_i|_i|_i|_i|_gggd|_t |_ |j j d|j j ddS)NT)inetipip6) _fwZrestore_command_existsZavailable_tablesrule_to_handlerule_ref_countrich_rule_priority_countspolicy_priority_countszone_source_index_cachecreated_tablesrrIZset_echo_outputZset_handle_output)selffwr4r4r5__init__s znftables.__init__cCsxdD]}||krPqWd||dkr`||ddd||dddf}||dd=n(d||dkrd}||dd=ndS||dd }|r|dkr||kr|||kr||j|n|dkr||krg||<|r(|||kr||j|||jd d d ||j|}n|jjr8d }n t||}||}||=|d krf||d<n |d8}||d<||ddd<dS)Naddinsertdeletez%%ZONE_SOURCE%%rulezoneaddressz%%ZONE_INTERFACE%%familycSs|dS)Nrr4)xr4r4r5sz3nftables._run_replace_zone_source..)keyrr<index)rWrXrY)remover2sortrarM_allow_zone_driftinglen)rTrZrRverbZ zone_sourcer]ra _verb_snippetr4r4r5_run_replace_zone_sourcesD        z!nftables._run_replace_zone_sourcecCsBd|krdtj|diSd|kr4dtj|diSttddS)NrXrYrWzFailed to reverse rule)copydeepcopyr r )rTdictr4r4r5 reverse_rules znftables.reverse_rulec Csxd D]}||krPqW|||dkr||d|}||d|=t|tkr^ttd||dd||ddf}|dkr||ks|||ks|||dkrttd |||d 8<n||kri||<|||krd|||<d}xVt||jD]B}||kr"|dkr"P||||7}||kr|dkrPqW|||d 7<||} ||=|dkr| |d<n |d 8}| |d<||ddd <dS) NrWrXrYrZz%priority must be followed by a numberr]chainrz*nonexistent or underflow of priority countr<ra)rWrXrY)r+intr r r sortedkeys) rTrZZpriority_countstokenrfpriorityrmraprgr4r4r5_set_rule_replace_prioritysD          z#nftables._set_rule_replace_prioritycCsfx`d D]X}||krd||krtj||d}xd D]}||kr6||=q6Wtj|dd }|SqWdS) NrWrXrYrZrahandlepositionT)Z sort_keys)rWrXrY)rarurv)rirjjsondumps)rTrZrfrule_keyZnon_keyr4r4r5 _get_rule_keys   znftables._get_rule_keycCsLdddddg}dddg}g}g}tj|j}tj|j}tj|j} |jj} x|D]} t| tkrvtt d| x|D]} | | kr|Pq|W| | krtt d| |j | } | | krDt j d|j| | | | dkr| | d 7<qVnX| | d kr | | d 8<qVn6| | d kr,| | d 8<ntt d | | | fn| r\| dkr\d | | <|j| tj| }| rttd|| d d || d d <|j||d |j||d|j|| | dkrdd |dd d|dd d|dd d|j| dii}|j|qVWdddd iig|i}t jdkrVt jd|jtj||jj|\}}}|dkrtdd|tj|f||_||_| |_| |_d}x|D]} |d 7}|j | } | s̐qd| kr|j| =|j| =qx"|D]} | |d|krPqW| |d|kr$q|d|| d d|j| <qWdS)NrWrXrYflushreplacez#rule must be a dictionary, rule: %szno valid verb found, rule: %sz%s: prev rule ref cnt %d, %sr<z)rule ref count bug: rule_key '%s', cnt %drZexprz%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%r]tablerm)r]r~rmrurIZmetainfoZjson_schema_versionr@z.%s: calling python-nftables with JSON blob: %srz'%s' failed: %s JSON blob: %szpython-nftablesru)rirjrPrQrRrOr+rkr r r rzrZdebug2 __class__r2listr(rtrhrNZgetDebugLogLevelZdebug3rwrxrIZjson_cmd ValueError)rTrules log_deniedZ _valid_verbsZ_valid_add_verbsZ_deduplicated_rulesZ_executed_rulesrPrQrRrOrZrfryZ_ruleZ json_blobZrcr!errorrar4r4r5 set_rules+s             &         znftables.set_rulescCs|j|g|dS)N)r)rTrZrr4r4r5set_rulesznftables.set_ruleNcCs|r |gStjS)N)IPTABLES_TO_NFT_HOOKrp)rTr~r4r4r5get_available_tablessznftables.get_available_tablescCsFg}xdD]6}|jdddtd d |fd |dtd ddiiq:W|dkr|jdddtdii|jdjtx>dD]6}|jdddtd d |fd |dtd ddiiqW||jd7}nz|dkrfx4|jdD]&}|j|}||jkr |j|q W||jt7}t|jdkrp|jdjtn t t d|S)NZPANICrWr~rJ)r]rrr!rmz%s_%sr%r(i,r<drop)r]r~rr+rpriopolicyDROPrr rTACCEPTFznot implemented)rr!i)rr r!) r2rrSNFT_HOOK_OFFSETrrzrNrrbr r )rTrrrrZrr4r4r5build_set_policy_rulessH               znftables.build_set_policy_rulescCs<t}x,|r|gntjD]}|jt|jqWt|S)N)rICMP_TYPES_FRAGMENTSrpupdater)rTipvZ supportedZ_ipvr4r4r5supported_icmp_typessznftables.supported_icmp_typescCs>g}x4dD],}|jdd|tdii|j|jtq W|S)NrJrKrLrWr~)r]r)rJrKrL)r2rrS)rTZdefault_tablesr]r4r4r5build_default_tabless   znftables.build_default_tablesoffcCsg}xtdjD]}|jdddtd|ddtd|dtd|d d iixz|jjrld d d dgnd d dgD]X}|jdddtd||fdii|jdddtd|ddd||fiigdiiqvWqWxd?D]}xtdjD]}|jdd|td|ddtd|dtd|d d iix~|jjrJd d d dgnd d dgD]Z}|jdd|td||fdii|jdd|td|ddd||fiigdiiqTWqWqWxVtdjD]F}|jdddtd|ddtd|dtd|d d iiqW|jdddtddddddiid d!d"d#gid$id%digdii|jdddtdddddd&iid d'd$id%digdii|jdddtdddd(dd)iid*d+d$id%digdiix~|jjrd d d dgnd d dgD]Z}|jdddtd,d|fdii|jdddtddddd,d|fiigdiiqW|d-kr|jdddtddddddiid d!d.gid$i|j|d/d0d1iigdii|jdddtddddddiid d!d.gid$id2digdii|d-kr$|jdddtdd|j|d/d0d3iigdii|jdddtddd4d5d6d7igdii|jdddtdd8ddddiid d!d"d#gid$id%digdii|jdddtdd8dddd&iid d'd$id%digdii|jdddtdd8dd(dd)iid*d+d$id%digdiixbd@D]Z}|jdddtd,d8|fdii|jdddtdd8ddd,d8|fiigdiiqWxdAD]}xz|jjrd d gnd gD]^}|jdddtd;d8||fdii|jdddtdd8ddd;d8||fiigdiiqWqvWxbdBD]Z}|jdddtd,d8|fdii|jdddtdd8ddd,d8|fiigdiiqW|d-kr|jdddtdd8ddddiid d!d.gid$i|j|d/d0d1iigdii|jdddtdd8ddddiid d!d.gid$id2digdii|d-kr6|jdddtdd8|j|d/d0d3iigdii|jdddtdd8d4d5d6d7igdii|jdddtdd<ddddiid d!d"d#gid$id%digdii|jdddtd=dd(dd>iid*d+d$id%digdiixbdCD]Z}|jdddtd,d<|fdii|jdddtdd<ddd,d<|fiigdiiqWxbdDD]Z}|jdddtd,d<|fdii|jdddtdd<ddd,d<|fiigdiiqHW|S)ENr&rWrmrJz mangle_%sr(z%srr<)r]r~rr+rr POLICIES_preZ ZONES_SOURCEZZONES POLICIES_postz mangle_%s_%s)r]r~rrZjumptarget)r]r~rmr}rKrLr'znat_%sz nat_%s_%sz filter_%sr"r)rr`rrrrr)r.r/r0rZstatusdnatmetaiifnamez==loz filter_%s_%srZinvalidrprefixzSTATE_INVALID_DROP: rzFINAL_REJECT: rejecticmpxzadmin-prohibited)r+r}r#INOUTzfilter_%s_%s_%sr$ filter_OUTPUToifname)rKrL)r)rr)r)r)r)rrpr2rrMrd_pkttype_match_fragment)rTrZ default_rulesrmZdispatch_suffixr] directionr4r4r5build_default_rules s $  (  &  .        &  &                 &   .   &               &   &znftables.build_default_rulescCs4|dkrdddgS|dkr dgS|dkr0ddgSgS) Nr(r" FORWARD_IN FORWARD_OUTr&rr'rr4)rTr~r4r4r5get_zone_table_chainss znftables.get_zone_table_chainsrJc  sdkr\dkr\g} | jj|||||dd | jj|||||dd | Sjjj|jdkrxdnddkrd krd nd } jjj|t| g} g} |r| jd d ddiiddt |idi|r| jd d ddiiddt |ididdd}|rlxT|D]L}dkrTjj j |}||krT||krTq| jj d|qW|rxT|D]L}dkrjj j |}||kr||krqx| jj d|qxWfdd}g} | rHx| D]P}| rxB| D]}| j|||qWn"dkr0|r0n| j||dqWn\dkrZ|rZnJ| rxB| D]}| j|d|qfWn"dkr|rn| j|dd| S)Nr'rJrK)r]rLrprepostrTFr)rr`rz==r)r.r/r0r)rGrHsaddrdaddrcsg}|r|j||r |j||jdddfiitdf|d}|jjrrdd|iiSdd|iiSdS) Nrrz%s_%sz%s_%s_POLICIES_%s)r]r~rmr}rWrZrY)r2rr_policy_priority_fragment)ingress_fragmentegress_fragmentexpr_fragmentsrZ)_policyrm chain_suffixrr]p_objrTr~r4r5_generate_policy_dispatch_rules    zRnftables.build_policy_ingress_egress_rules.._generate_policy_dispatch_rule) extend!build_policy_ingress_egress_rulesrMrZ get_policyrrpolicy_base_chain_namePOLICY_CHAIN_PREFIXr2rr[Z check_source_rule_addr_fragment)rTrrr~rmZingress_interfacesZegress_interfacesZingress_sourcesZegress_sourcesr]risSNATZingress_fragmentsZegress_fragmentsZ ipv_to_familysrcrdstrrrr4)rrmrrr]rrTr~r5rsv          z*nftables.build_policy_ingress_egress_rulesFc  Cs|dkrT|dkrTg} | j|j|||||||d| j|j|||||||d| S|dkrh|dkrhdnd} |jjj||t| d} d d d d d d d |} |t|d d kr|dt|d d}d} |dkr| dd|| fiig}n,ddd| iid|di| dd|| fiig}|rL| rLd}|td||f|d}|j|j nP|rnd}|td||f|d}n.d}|td||f|d}|s|j|j |d|iigS)Nr'rJrKrLrTF)rrr)rrr"rrr$r<+*gotorz%s_%sr)rr`z==)r.r/r0rXz %s_%s_ZONES)r]r~rmr}rWrYrZ) r!build_zone_source_interface_rulesrMrrrrerr_zone_interface_fragment)rTrr[r interfacer~rmr2r]rrroptactionrrfrZr4r4r5rQs\     z*nftables.build_zone_source_interface_rulesc Csn|dkr|dkrg}|jdr6|j|tdd} nd} td|sTt|sT| dkrp|j|j||||||dtd|st|s| dkr|j|j||||||d|S|dkr|dkrd nd } |jjj ||t | d } d d d|} ddddddd|} |jj rd||f}n d||f}d}|t ||j | ||dd|| fiigd}|j|j||| d|iigS)Nr'rJzipset:rGrKrHrLrTF)rrXrY)TFrr)rrr"rrr$z%s_%s_ZONES_SOURCEz %s_%s_ZONESrrz%s_%s)r]r~rmr}rZ) startswith_set_get_familyrerrrbuild_zone_source_address_rulesrMrrrrdrrr_zone_source_fragment)rTrr[rr\r~rmr]rZ ipset_familyrrrrZzone_dispatch_chainrrZr4r4r5rsB    z(nftables.build_zone_source_address_rulesc Cs|dkrH|dkrHg}|j|j||||d|j|j||||d|Sddd|}|dkrj|dkrjd nd }|jjj||t|d } g}|j|d |td || fdiix0d!D](} |j|d |td|| | fdiiqWxDd"D]<} |j|d|td || fddd|| | fiigdiiqW|jjj|j } |jj dkr|dkr| d#kr| } | dkrhd} |j|d|td || f|j |jj ddd| | fiigdii|dkr| d$kr| d%kr|j } n | j di} |j|d|td || f| gdii|s|j|S)&Nr'rJrKrLrWrY)TFrTF)rrmz%s_%s)r]r~rrrdenyallowrz%s_%s_%srZrr)r]r~rmr}rr(REJECT %%REJECT%%rrz"filter_%s_%s: "r)rrrrr)rrrrr)rrr)rrrr)rr)rbuild_policy_chain_rulesrMrrrr2rZ _policiesrget_log_deniedr_reject_fragmentlowerreverse)rTrrr~rmr]rrrrrrZ log_suffixtarget_fragmentr4r4r5rsZ      &             z!nftables.build_policy_chain_rulescCs<|dkr iS|d kr,ddddiid |d iSttd |dS) Nallunicast broadcast multicastr)rr`pkttypez==)r.r/r0zInvalid pkttype "%s")rrr)r r )rTrr4r4r5rs  z nftables._pkttype_match_fragmentcCsddddiddddiddddiddddiddddiddddiddddiddddiddddiddddiddd diddd diddd diddd didd d diddd diddd diddd diddd diddddiddddidddiidddiid}||S)Nrr7zhost-prohibited)r+r}znet-prohibitedzadmin-prohibitedrFznet-unreachablezhost-unreachablezport-unreachablerzprot-unreachablezaddr-unreachablezno-router+z tcp reset)zicmp-host-prohibitedz host-prohibzicmp-net-prohibitedz net-prohibzicmp-admin-prohibitedz admin-prohibzicmp6-adm-prohibitedzadm-prohibitedzicmp-net-unreachablez net-unreachzicmp-host-unreachablez host-unreachzicmp-port-unreachablezicmp6-port-unreachablez port-unreachzicmp-proto-unreachablez proto-unreachzicmp6-addr-unreachablez addr-unreachzicmp6-no-routezno-routez tcp-resetztcp-rstr4)rTZ reject_typeZfragsr4r4r5_reject_types_fragments0                      znftables._reject_types_fragmentcCsddddiS)Nrrzadmin-prohibited)r+r}r4)rTr4r4r5rsznftables._reject_fragmentcCs ddddiiddddgid iS) Nr)rr`l4protoz==rr7rF)r.r/r0r4)rTr4r4r5_icmp_match_fragment"s znftables._icmp_match_fragmentcCsP|siSddddd}|j\}}|||d}|j}|dk rH||d<d|iS) NsecondZminuteZhourZday)smhd)rateZperburstlimit)Z value_parseZ burst_parse)rTrZ rich_to_nftrZdurationrrr4r4r5_rich_rule_limit_fragment's  z"nftables._rich_rule_limit_fragmentcCst|jtttgkrn<|jrHt|jtttt gkrRt t dt|jn t t d|j dkrt|jttgkst|jtt gkrdSt|jtgkst|jttgkrdSn|j dkrdSdSdS)NzUnknown action %szNo rule action specified.rrrrr) r+elementrrrrrrrrr r rr)rT rich_ruler4r4r5_rich_rule_chain_suffix?s    z nftables._rich_rule_chain_suffixcCs>|j r|j rttd|jdkr(dS|jdkr6dSdSdS)NzNot log or auditrrrr)rauditr r rr)rTrr4r4r5 _rich_rule_chain_suffix_from_logUs   z)nftables._rich_rule_chain_suffix_from_logcCsddiS)Nz%%ZONE_INTERFACE%%r4)rTr4r4r5r`sz!nftables._zone_interface_fragmentcCsNtd|rt|}n,td|r@|jd}t|dd|d}d||diS)NrH/rr<z%%ZONE_SOURCE%%)r[r\)rrrsplit)rTr[r\Z addr_splitr4r4r5rcs     znftables._zone_source_fragmentcCs d|jiS)Nz%%POLICY_PRIORITY%%)rr)rTrr4r4r5rksz"nftables._policy_priority_fragmentcCs| s|jdkriSd|jiS)Nrz%%RICH_RULE_PRIORITY%%)rr)rTrr4r4r5_rich_rule_priority_fragmentnsz%nftables._rich_rule_priority_fragmentc Cs|js iS|jjj||t}ddd|}|j|}i} |jjrPd|jj| d<|jjr|d|jjkrhdn|jj} d| | d<d td |||f||j |jj d | igd } | j |j ||d | iiS)NrWrY)TFz%srZwarningwarnlevelrJz%s_%s_%sr)r]r~rmr}rZ) rrMrrrrrrrrrrr) rTrrrr~rrrrZ log_optionsrrZr4r4r5_rich_rule_logss&    znftables._rich_rule_logc Cs|js iS|jjj||t}ddd|}|j|}dtd|||f||j|jjdddiigd } | j |j ||d | iiS) NrWrY)TFrJz%s_%s_%srrr)r]r~rmr}rZ) rrMrrrrrrrrr) rTrrrr~rrrrrZr4r4r5_rich_rule_audits   znftables._rich_rule_auditc Cs|js iS|jjj||t}ddd|}|j|}d|||f} t|jtkr\ddi} nt|jtkr|jjr|j |jj} nddi} nt|jt krddi} nt|jt krHd}|jjj||t}d|||f} |jj j d } t| d kr,dd d d iiddd d d ii| d gi| dgidi} ndd d d ii| ddi} nttdt|jdt| ||j|jj| gd} | j|j||d| iiS)NrWrY)TFz%s_%s_%srrrr&rr<rr`mark^&r)r`valuezUnknown action %srJ)r]r~rmr}rZ)rrMrrrrr+rrrrrrrrer r rrrrr) rTrrrr~rrrrrmZ rule_actionrrZr4r4r5_rich_rule_actionsB     , znftables._rich_rule_actioncCs|jdr0|j|tddd|kr(dnd|St|r>d}ntd|rNd}nvtd|rd}tj|dd}d |jj |j d i}nDtd |rd }t |}n,d }|j d }d t |dt |dd i}dd||di|rdnd|diSdS)Nzipset:rTFetherrGrK)strictr)addrrerHrLrrr<r)r*)r,r-z!=z==)r.r/r0)r_set_match_fragmentrerrr ipaddressZ IPv4NetworkZnetwork_addressZ compressedZ prefixlenrrrn)rTZ addr_fieldr\invertr]Znormalized_addressZaddr_lenr4r4r5rs( &      znftables._rule_addr_fragmentcCs6|siS|d krttd|ddddiid|d iS) NrGrHzInvalid familyr)rr`nfprotoz==)r.r/r0)rGrH)r r )rTZ rich_familyr4r4r5_rich_rule_family_fragments  z#nftables._rich_rule_family_fragmentcCs8|siS|jr|j}n|jr&d|j}|jd||jdS)Nzipset:r)r)r ipsetrr)rTZ rich_destr\r4r4r5_rich_rule_destination_fragments z(nftables._rich_rule_destination_fragmentcCsZ|siS|jr|j}n2t|dr.|jr.|j}nt|drH|jrHd|j}|jd||jdS)Nmacrzipset:r)r)r hasattrrrrr)rTZ rich_sourcer\r4r4r5_rich_rule_source_fragments z#nftables._rich_rule_source_fragmentcCsPt|}t|tr$|dkr$ttn(t|dkr8|dSd|d|dgiSdS)Nrr<range)r isinstancernr rre)rTportrr4r4r5_port_fragments   znftables._port_fragmentc Csbddd|}d}|jjj||t} g} |r>| j|j|j|rT| j|jd||r|| j|j|j | j|j |j | jdd|dd id |j |d i| st |jtkr| jdd d diiddddgid ig} |r0| j|j||||| | j|j||||| | j|j||||| n.| j|ddtd|| f| ddigdii| S)NrWrY)TFr(rr)r*dport)r,r-z==)r.r/r0rr`rrrnew untrackedrZrJz %s_%s_allowr)r]r~rmr})rMrrrr2rr]rr destinationrsourcerr+rrrrrr) rTrrprotorrrrr~rrrr4r4r5build_policy_ports_ruless:   z!nftables.build_policy_ports_rulesc CsZddd|}d}|jjj||t}g} |r>| j|j|j|rT| j|jd||r|| j|j|j | j|j |j | jdddd iid |d i| st |j tkr| jdd dd iiddddgid ig} |r(| j|j||||| | j|j||||| | j|j||||| n.| j|ddtd||f| ddigdii| S)NrWrY)TFr(rr)rr`rz==)r.r/r0rrrrrrrZrJz %s_%s_allowr)r]r~rmr})rMrrrr2rr]rrrrrr+rrrrrr) rTrrr,rrrr~rrrr4r4r5build_policy_protocol_rules2s8   z$nftables.build_policy_protocol_rulesc Csbddd|}d}|jjj||t} g} |r>| j|j|j|rT| j|jd||r|| j|j|j | j|j |j | jdd|dd id |j |d i| st |jtkr| jdd d diiddddgid ig} |r0| j|j||||| | j|j||||| | j|j||||| n.| j|ddtd|| f| ddigdii| S)NrWrY)TFr(rr)r*sport)r,r-z==)r.r/r0rr`rrrrrrZrJz %s_%s_allowr)r]r~rmr})rMrrrr2rr]rrrrrrr+rrrrrr) rTrrrrrrrr~rrrr4r4r5build_policy_source_ports_rulesUs:   z(nftables.build_policy_source_ports_rulesc Csd}|jjj||t} ddd|} g} |rR| jdddtd||f||diig} |rl| j|jd || jd d |d d id|j|di| jdd||fi| j| ddtd| | dii| S)Nr(rWrY)TFz ct helperrJz helper-%s-%s)r]r~rr+r,rr)r*r)r,r-z==)r.r/r0rZzfilter_%s_allow)r]r~rmr})rMrrrr2rrr) rTrrrrrZ helper_nameZmodule_short_namer~rrrrr4r4r5build_policy_helper_ports_ruleszs.    z(nftables.build_policy_helper_ports_rulesc Csddd|}|jjj||t}g} |rv|t|ddkrT|dt|dd}ddd d iid |d id dig} n|jd|d dig} dtd|| d} | j|d| ii| S)NrWrY)TFr<rrr)rr`rz==)r.r/r0rrrJzfilter_%s_allow)r]r~rmr}rZ)rMrrrrerrr2) rTrr[rr~rrrrrr}rZr4r4r5build_zone_forward_ruless"  z!nftables.build_zone_forward_rulesc Csd}|jjj||tdd}ddd|}g}|r`|j|j|j|j|j|j|j |} nd} |t d|| f|d d d d iid ddiddigd} | j |j ||d| iigS)Nr'T)rrWrY)TFrz nat_%s_%sr)rr`rz!=r)r.r/r0Z masquerade)r]r~rmr}rZ) rMrrrr2rrrrrrrr) rTrrr]rr~rrrrrZr4r4r5"_build_policy_masquerade_nat_ruless&   z+nftables._build_policy_masquerade_nat_rulesc Cs^g}|rD|jr|jdks,|jrDtd|jjrD|j|j||d|nV|r|jrX|jdksl|jrtd|jjr|j|j||d|n|j|j||d|d}|jjj||t }ddd|}g}|r|j |j |j |j |j |j|j|} nd } d td || f|d d ddiiddddgididdigd} | j|j||j |d| ii|S)NrHrLrGrKr(rWrY)TFrrJz filter_%s_%sr)rr`rrrrr)r.r/r0r)r]r~rmr}rZ)r]rrr rr&rMrrrr2rrrrrrr) rTrrrrr~rrrrrZr4r4r5build_policy_masquerade_ruless8   z&nftables.build_policy_masquerade_rulesc Cs$d} |jjj|| t} ddd|} g} |r\| j|j|j| j|j|j|j |} nd} | jdd|dd id |j |d i|rt d |rt |}|r|d kr| jd||j |diq| jdd|iin| jdd|j |ii|t d| | f| d}|j|j|| d|iigS)Nr'rWrY)TFrr)r*r)r,r-z==)r.r/r0rHrr)r rr r;rz nat_%s_%s)r]r~rmr}rZ)rMrrrr2rrrrrrrrrrr)rTrrrr,toaddrtoportr]rr~rrrrrZr4r4r5$_build_policy_forward_port_nat_ruless4     z-nftables._build_policy_forward_port_nat_rulesc Csg}|rF|jr|jdks&|rFtd|rF|j|j||||||d|n|r|jrZ|jdksh|rtd|r|j|j||||||d|nL|rtd|r|j|j||||||d|n|j|j||||||d||S)NrHrLrGrK)r]rrr*) rTrrrr,r)r(rrr4r4r5build_policy_forward_port_ruless    z(nftables.build_policy_forward_port_rulescCs2|t|krt||Sttd||j|fdS)Nz)ICMP type '%s' not supported by %s for %s)rr r r)rTrZ icmp_typer4r4r5_icmp_types_to_nft_fragments(s  z%nftables._icmp_types_to_nft_fragmentscCsBd}|jjj||t}ddd|}|r6|jr6|j}n<|jrjg}d|jkrT|jdd|jkrr|jdnddg}g} x|D]} |jjj|rd||f} ddi} nd ||f} |j} g} |r| j|j |j | j|j |j| j|j |j | j|j| |j|r| j|j||||| | j|j||||| |jrf| j|j||||| nN|j|}d td |||f| |jgd }|j|j|| j|d |iiq~|jjdkr|jjj| r| j|d d t| | |j|jjddd||fiigd ii| j|d d t| | | gd iiq~W| S)Nr(rWrY)TFrGrHz %s_%s_allowrz %s_%s_denyrJz%s_%s_%s)r]r~rmr}rZrrrz"%s_%s_ICMP_BLOCK: ")rMrrripvsrr2query_icmp_block_inversionrrr]rrrrr,rrrrrrrrrrr)rTrrZictrr~rrr-rrZ final_chainrrrrZr4r4r5build_policy_icmp_block_rules/sb          " " z&nftables.build_policy_icmp_block_rulescCsd}|jjj||t}g}ddd|}|jjj|r@|j}nddi}|j|ddtd||fd |j|gd ii|jj d kr|jjj|r|j|ddtd||fd |j|j |jj d d d||fiigd ii|S)Nr(rWrY)TFrrZrJz%s_%sr9)r]r~rmrar}rrrz%s_%s_ICMP_BLOCK: ) rMrrrr.rr2rrrr)rTrrr~rrrrr4r4r5'build_policy_icmp_block_inversion_rulesks,      z0nftables.build_policy_icmp_block_inversion_rulesc Csg}ddddiidddiddd d d gd d idddig}|dkrV|jdddii|jddi|jdddtd|dii|jdddtddddddiddddgidid digdii|S)!Nr)rr`rz==rH)r.r/r0ZfibrZiifrZoif)flagsresultFrrrzrpfilter_DROP: rrXrZrJZfilter_PREROUTING)r]r~rmr}r*rFr+)r,r-rznd-router-advertznd-neighbor-solicitr)r2r)rTrrrr4r4r5build_rpfilter_ruless0     znftables.build_rpfilter_rulesc Csddddddddd g }d d |D}d d dddidd|idig}|jjd"krb|jdddii|j|jdg}|jdddtdd|dii|jdddtd d!|dii|S)#Nz ::0.0.0.0/96z::ffff:0.0.0.0/96z2002:0000::/24z2002:0a00::/24z2002:7f00::/24z2002:ac10::/28z2002:c0a8::/32z2002:a9fe::/32z2002:e000::/19cSs2g|]*}d|jddt|jdddiqS)rrrr<)r re)rrn).0r^r4r4r5 sz5nftables.build_rfc3964_ipv4_rules..r)r*rLr)r,r-z==r)r.r/r0rrrrzRFC3964_IPv4_REJECT: z addr-unreachrWrZrJrr<)r]r~rmrar}Zfilter_FORWARDrB)rr)rMZ _log_deniedr2rr)rTZ daddr_setrrr4r4r5build_rfc3964_ipv4_ruless:   z!nftables.build_rfc3964_ipv4_rulescCsd}g}|j|j|j|j|j|j|j|j|jg}|j|j||||||j|j||||||j|j ||||||S)Nr() r2rr]rrrrrrr)rTrrrr~rrr4r4r5*build_policy_rich_source_destination_rulessz3nftables.build_policy_rich_source_destination_rulescCs|dkr dSdS)NrGrHebTF)rGrHr8r4)rTrr4r4r5is_ipv_supportedsznftables.is_ipv_supportedc Csddd}||||ddg||dd||g||dd||g||dg||||||g||ddg||dd||g||dgdd }||kr||Sttd |dS) NZ ipv4_addrZ ipv6_addr)rGrHZ inet_protoZ inet_servicerZifnameZ ether_addr) zhash:ipz hash:ip,portzhash:ip,port,ipzhash:ip,port,netz hash:ip,markzhash:netz hash:net,netz hash:net,portzhash:net,port,netzhash:net,ifacezhash:macz!ipset type name '%s' is not valid)r r )rTrr+Zipv_addrtypesr4r4r5_set_type_lists"    znftables._set_type_listc Cs|rd|kr|ddkrd}nd}t||j||d}x0|jddjdD]}|dkrLd g|d <PqLW|rd|kr|d|d<d|kr|d|d<g}x0dD](}d|i} | j||jdd| iiqW|S)Nr]inet6rHrG)r~rr+:r<,rKnetrZintervalr1ZtimeoutZmaxelemsizerJrLrWr)rKr?r)rJrKrL)rr;rrr2) rTrr+optionsrZset_dicttrr]Z rule_dictr4r4r5build_set_create_ruless*     znftables.build_set_create_rulescCs$|j|||}|j||jjdS)N)rCrrMr)rTrr+rArr4r4r5 set_createsznftables.set_createcCs8x2dD]*}dd|t|dii}|j||jjqWdS)NrJrKrLrYr)r]r~r)rJrKrL)rrrMr)rTrr]rZr4r4r5 set_destroys   znftables.set_destroycCs6|jjj|jjddjd}g}xtt|D]}||dkrr|jdddii|jdd |rdd nd d iq2||dkr|jd|j||rdndd iq2||dkr|jdd|rdndiiq2||dkr|jdddiiq2t d||q2Wdt|dkrd|in|d|r&dndd|diS)Nr=r<r>rrr`rr*Zthrr")r,r-rKr?rrrZifacerrrz-Unsupported ipset type for match fragment: %sr)concatrz!=z==@)r.r/r0)rKr?r) rMr get_ipsetr+rrrer2rr )rTrZ match_destr type_formatr3ir4r4r5r  s$      znftables._set_match_fragmentc CsN|jjj|}|jjddjd}|jd}t|t|krHttdg}xtt|D]}||dkr,y||j d}Wn&t k r|j d||} Yn,X|j ||d||||dd} y| j d}Wn t k r|j | Yn(X|j d| d|| |ddgiq\||dkr d||krb|j d||jdiny||j d }WnLt k r||} d |j kr|j d d krt | } |j | Yn^X||d|} d |j kr|j d d krt | } |j d| t|||dddiq\|j ||q\Wt|dkrJd|igS|S)Nr=r<r>z+Number of values does not match ipset type.rZtcp-rrKr?rr]r<r)r rerF)rKr?)rMrrHr+rrer rrrarr2rArrn) rTrentryobjrIZ entry_tokensZfragmentrJraZport_strr r4r4r5_set_entry_fragment7sL  ("znftables._set_entry_fragmentc Cs>g}|j||}x(dD] }|jdd|t||diiqW|S)NrJrKrLrWr)r]r~relem)rJrKrL)rNr2r)rTrrLrrr]r4r4r5build_set_add_rulesks   znftables.build_set_add_rulescCs"|j||}|j||jjdS)N)rPrrMr)rTrrLrr4r4r5set_addus znftables.set_addcCsF|j||}x4dD],}dd|t||dii}|j||jjqWdS)NrJrKrLrYr)r]r~rrO)rJrKrL)rNrrrMr)rTrrLrr]rZr4r4r5 set_deleteys   znftables.set_deletecCs4g}x*dD]"}dd|t|dii}|j|q W|S)NrJrKrLr{r)r]r~r)rJrKrL)rr2)rTrrr]rZr4r4r5build_set_flush_ruless  znftables.build_set_flush_rulescCs |j|}|j||jjdS)N)rSrrMr)rTrrr4r4r5 set_flushs znftables.set_flushcCsJ|jjj|}|jdkrd}n(|jrBd|jkrB|jddkrBd}nd}|S)Nzhash:macr r]r<rLrK)rMrrHr+rA)rTrrr]r4r4r5rs znftables._set_get_familyc Csg}|j|j||||j|j|d}x^|D]D}|j|j|||d7}|dkr2|j||jj|jd}q2W|j||jjdS)Nrr<i)rrCrSrPrrMrclear) rTZset_nameZ type_nameZentriesZcreate_optionsZ entry_optionsrchunkrLr4r4r5 set_restores znftables.set_restore)N)N)r)rJ)FrJ)rJ)rJ)F)NN)NN)NN)NN)N)N)N)N)N)F)N)N)F)NN)I__name__ __module__ __qualname__rZpolicies_supportedrVrhrlrtrzrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr r!r#r$r%r&r'r*r+r,r/r0r3r6r7r9r;rCrDrEr rNrPrQrRrSrTrrWr4r4r4r5rIs/.`  4  R i ; - 9   +     $ $ $   ' $  < #   4   rIiji)N)(Z __future__rrirwr Zfirewall.core.loggerrZfirewall.functionsrrrrrZfirewall.errorsr r r r r rrZfirewall.core.richrrrrrrrZnftables.nftablesrrrrrrr6robjectrIr4r4r4r5s  $$                                         PKpge[B'__pycache__/helper.cpython-36.opt-1.pycnu[3 g$@s dZdZdS)zThe helper maxnamelen N)__doc__ZHELPER_MAXNAMELENrr/usr/lib/python3.6/helper.pysPKpge[#pqq#__pycache__/__init__.cpython-36.pycnu[3 g@sdS)Nrrr/usr/lib/python3.6/__init__.pysPKpge[#pqq)__pycache__/__init__.cpython-36.opt-1.pycnu[3 g@sdS)Nrrr/usr/lib/python3.6/__init__.pysPKpge[G@ @ (__pycache__/modules.cpython-36.opt-1.pycnu[3 g@sBdZdgZddlmZddlmZddlmZGdddeZ dS)zmodules backendmodules)runProg)log)COMMANDSc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)rcCstd|_td|_dS)NZmodprobeZrmmod)r _load_command_unload_command)selfr /usr/lib/python3.6/modules.py__init__s zmodules.__init__cCs d|jS)Nz%s) __class__)rr r r __repr__$szmodules.__repr__cCsg}i}ytddp}xh|D]`}|s&P|j}|j}|j|d|ddkrp|djddd ||d<qg||d<qWWdQRXWntk rYnX||fS) z6 get all loaded kernel modules and their dependencies z /proc/modulesrr-,N)openstripsplitappendFileNotFoundError)rmodsdepsflineZsplitsr r r loaded_modules's     zmodules.loaded_modulescCs"tjd|j|j|t|j|gS)Nz %s: %s %s)rdebug2r rr)rmoduler r r load_module<szmodules.load_modulecCs"tjd|j|j|t|j|gS)Nz %s: %s %s)rrr rr)rrr r r unload_module@szmodules.unload_modulecCsT||kr dSx0||D]$}|j|||||kr|j|qW||krP|j|dS)z get all dependants of a module N)get_depsr)rrrretmodr r r r"Dszmodules.get_depscCsg}|j\}}|jd||x*dD]"}||kr$|j||jd|q$Wx^|D]V}|dks|jds|jd s|jd s|jd s|jd s|jd rP|j|||qPW|S)z) get all loaded firewall-related modules Z nf_conntracknf_conntrack_ipv4nf_conntrack_ipv6r ip_tables ip6_tablesebtablesZiptable_Z ip6table_Znf_Zxt_Zipt_Zip6t_)r%r&r)r'r(r))rr"removeinsert startswith)rrZmods2rZbad_bad_moduler$r r r get_firewall_modulesOs    zmodules.get_firewall_modulescCs>x8|jD],}|j|\}}|dkr tjd||fq WdS)z% unload all firewall-related modules rz Failed to unload module '%s': %sN)r-r!rZdebug1)rrZstatusr#r r r unload_firewall_modulesdszmodules.unload_firewall_modulesN) __name__ __module__ __qualname__r r rr r!r"r-r.r r r r rs N) __doc____all__Zfirewall.core.progrZfirewall.core.loggerrZfirewall.configrobjectrr r r r s    PKpge[k-N#__pycache__/ebtables.cpython-36.pycnu[3 g$@s&dgZddlZddlmZddlmZddlmZm Z m Z ddl m Z ddl mZddlmZmZddlZd gd d d gd d dgdZiZiZiZxejD]tZgee<eee<x\eeD]PZeejdeeejdeefeejdeeejdeqWqWGdddeZdS)ebtablesN)runProg)log)tempFilereadfile splitArgs)COMMANDS) ipXtables) FirewallError INVALID_IPVZBROUTINGZ PREROUTINGZ POSTROUTINGZOUTPUTZINPUTZFORWARD)ZbrouteZnatfilterz -N %s_directz-I %s 1 -j %s_directz-I %s_direct 1 -j RETURNz %s_directc@seZdZdZdZdZddZddZddZd d Z d d Z d dZ ddZ ddZ ddZddZddZddZddZddZd/d d!Zd"d#Zd$d%Zd&d'Zd(d)Zd0d+d,Zd-d.ZdS)1rZebFcCsBt|j|_td|j|_|j|_|j|_|jg|_ dS)Nz %s-restore) ripv_command_restore_command_detect_restore_noflush_optionZrestore_noflush_option_detect_concurrent_optionconcurrent_option fill_existsavailable_tables)selfr/usr/lib/python3.6/ebtables.py__init__9s    zebtables.__init__cCs$tjj|j|_tjj|j|_dS)N)ospathexistsrZcommand_existsrZrestore_command_exists)rrrrrAszebtables.fill_existscCs(d}t|jddg}|ddkr$d}|S)Nz --concurrentz-Lr)rr)rrretrrrrEs  z"ebtables._detect_concurrent_optionc Cs.g}y|j|dWntk r(dSXdS)NoffFT) set_rules ValueError)rrulesrrrrOs z'ebtables._detect_restore_noflush_optioncCsg}|jr |j|kr |j|j|dd|D7}tjd|j|jdj|t|j|\}}|dkr~td|jdj||f|S)NcSsg|] }d|qS)z%sr).0itemrrr ^sz"ebtables.__run..z %s: %s %s rz'%s %s' failed: %s) rappendrdebug2 __class__rjoinrr )rargsZ_argsstatusrrrrZ__runYs zebtables.__runcCs(x"dD]}||krttd|qWdS)N %%REJECT%%%%ICMP%% %%LOGTYPE%%z'%s' invalid for ebtables)r,r-r.)r r )rrulestrrrr_rule_validatefs zebtables._rule_validatecCs|tko|t|kS)N)BUILT_IN_CHAINS)rr tablechainrrris_chain_builtinlszebtables.is_chain_builtincCsJg}|r4|jd|d|g|jd|d|dddgn|jd|d|g|S)Nz-tz-Nz-I1z-jZRETURNz-X)r&)raddr3r4r!rrrbuild_chain_rulesps zebtables.build_chain_rulescCs8d|g}|r |d|t|g7}n |d|g7}||7}|S)Nz-tz-Iz-D)r0)rr7r3r4indexr*r/rrr build_rule{s  zebtables.build_rulecCs tj|S)N)r Zcommon_reverse_rule)rr*rrr reverse_ruleszebtables.reverse_rulecCstj|dS)N)r Zcommon_check_passthrough)rr*rrrcheck_passthroughszebtables.check_passthroughcCs tj|S)N)r Zcommon_reverse_passthrough)rr*rrrreverse_passthroughszebtables.reverse_passthroughc Cs<t}d}i}x|D]}|dd}|j|xTdD]L}y|j|} Wntk rZYq4Xt|| dkr4|j| |j| }q4Wx^tt|D]N} xHtjD]>} | || kr|| j do|| j d rd|| || <qWqW|j |gj |qWxD|D]<}|j d|x&||D]}|j dj|d qWqW|jtj|j} tjd |j|jd |j| jfg} | j d t|j| |jd \} }tjdkrt|j}|dk rd} xH|D]@}tjd| |fddd|j d stjddd| d7} qWtj|j| dkr8td|jdj| |fdS)Nr -t--table"z"%s"z*%s r% z %s: %s %sz%s: %dz --noflush)stdinz%8d: %sr)nofmtnlr)rEz'%s %s' failed: %s)r>r?)rr1r9r lenpoprangestringZ whitespace startswithendswith setdefaultr&writer)closerstatnamerr'r(rst_sizerZgetDebugLogLevelrZdebug3unlink)rr! log_deniedZ temp_filer3Z table_rulesZ_ruler/opticrPr*r+rlineslinerrrrsZ                zebtables.set_rulescCs|j||j|S)N)r1_ebtables__run)rr/rTrrrset_rules zebtables.set_ruleNc Csg}|r|gntj}xp|D]h}||jkr6|j|qy*|jd|dg|jj||j|Wqtk rtjd|YqXqW|S)Nz-tz-Lz#ebtables table '%s' does not exist.)r2keysrr&rZr rZdebug1)rr3rZtablesrrrget_available_tabless    zebtables.get_available_tablescCsiS)Nr)rr3rrrget_zone_table_chainsszebtables.get_zone_table_chainscCsFg}xs.     PKpge[EL%__pycache__/icmp.cpython-36.opt-1.pycnu[3 g #@sddddgZddddddd d d d d dddddddddddddddddddd d!d"d#d$"Zd%d&d'd(d)dddd*d+d,d,d-d-d.d/d0d0d1d1d2d3Zd4d5Zd6dZd7d8Zd9dZd:S); ICMP_TYPES ICMPV6_TYPEScheck_icmp_typecheck_icmpv6_typez0/0z3/0z3/1z3/2z3/3z3/4z3/5z3/6z3/7z3/9z3/10z3/11z3/12z3/13z3/14z3/15z4/0z5/0z5/1z5/2z5/3z8/0z9/0z10/0z11/0z11/1z12/0z12/1z13/0z14/0z17/0z18/0)"z echo-replypongznetwork-unreachablezhost-unreachablezprotocol-unreachablezport-unreachablezfragmentation-neededzsource-route-failedznetwork-unknownz host-unknownznetwork-prohibitedzhost-prohibitedzTOS-network-unreachablezTOS-host-unreachablezcommunication-prohibitedzhost-precedence-violationzprecedence-cutoffz source-quenchznetwork-redirectz host-redirectzTOS-network-redirectzTOS-host-redirectz echo-requestpingzrouter-advertisementzrouter-solicitationzttl-zero-during-transitzttl-zero-during-reassemblyz ip-header-badzrequired-option-missingztimestamp-requestztimestamp-replyzaddress-mask-requestzaddress-mask-replyz1/0z1/1z1/3z1/4z2/0z4/1z4/2z128/0z129/0z133/0z134/0z135/0z136/0z137/0)zno-routezcommunication-prohibitedzaddress-unreachablezport-unreachablezpacket-too-bigzttl-zero-during-transitzttl-zero-during-reassemblyz bad-headerzunknown-header-typezunknown-optionz echo-requestrz echo-replyrzrouter-solicitationzrouter-advertisementzneighbour-solicitationzneigbour-solicitationzneighbour-advertisementzneigbour-advertisementZredirectcCs|tkr dSdS)NTF)r)_namer/usr/lib/python3.6/icmp.pycheck_icmp_nameVsr cCs|tjkrdSdS)NTF)rvalues)_typerrr r[s cCs|tkr dSdS)NTF)r)rrrr check_icmpv6_name`sr cCs|tjkrdSdS)NTF)rr )r rrr res N)__all__rrr rr rrrrr sxPKpge[qwט22*__pycache__/fw_direct.cpython-36.opt-1.pycnu[3 gW@sndgZddlmZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z Gd ddeZd S) FirewallDirect)LastUpdatedOrderedDict) ipXtables)ebtables)FirewallTransaction)log)errors) FirewallErrorc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dNddZ ddZ ddZ dOddZddZddZddZd d!ZdPd"d#ZdQd$d%Zd&d'Zd(d)Zd*d+ZdRd,d-ZdSd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;ZdTdd?Z!d@dAZ"dBdCZ#dDdEZ$dFdGZ%dHdIZ&dJdKZ'dLdMZ(dS)VrcCs||_|jdS)N)_fw_FirewallDirect__init_vars)selffwr/usr/lib/python3.6/fw_direct.py__init__'szFirewallDirect.__init__cCsd|j|j|j|jfS)Nz%s(%r, %r, %r)) __class___chains_rules_rule_priority_positions)r rrr__repr__+szFirewallDirect.__repr__cCs"i|_i|_i|_i|_d|_dS)N)rrr _passthroughs_obj)r rrrZ __init_vars/s zFirewallDirect.__init_varscCs |jdS)N)r )r rrrcleanup6szFirewallDirect.cleanupcCs t|jS)N)rr )r rrrnew_transaction;szFirewallDirect.new_transactioncCs ||_dS)N)r)r objrrrset_permanent_config@sz#FirewallDirect.set_permanent_configcCs*t|jt|jt|jdkr&dSdS)NrTF)lenrrr)r rrrhas_runtime_configurationCs"z(FirewallDirect.has_runtime_configurationcCsB|jr dSt|jjt|jjt|jjdkr>dSdS)NTrF)rrrget_all_chains get_all_rulesget_all_passthroughs)r rrrhas_configurationHs z FirewallDirect.has_configurationNcCsP|dkr|j}n|}|j|jj|jj|jjf||dkrL|jddS)NT)r set_configrrrr execute)r use_transaction transactionrrr apply_directQs   zFirewallDirect.apply_directc Csi}i}i}xL|jD]B}|\}}x4|j|D]&}|jj|||s,|j|gj|q,WqWxf|jD]\}|\}}}xL|j|D]>\} } |jj|||| | s|||krt||<| ||| | f<q|WqbWxP|jD]F}x@|j|D]2} |jj || s||krg||<||j| qWqW|||fS)N) rr query_chain setdefaultappendr query_rulerrquery_passthrough) r ZchainsrulesZ passthroughstable_idipvtablechainchain_idpriorityargsrrrget_runtime_configbs,      z!FirewallDirect.get_runtime_configcCs|j|j|jfS)N)rrr)r rrr get_configszFirewallDirect.get_configcCs|dkr|j}n|}|\}}}x||D]t}|\}} xf||D]Z} |j|| | sr nftables_enabledget_direct_backend_by_ipv our_chainsrZ OUR_CHAINSr rZ BUILTIN_CHAINzoneZzone_from_chainZ INVALID_CHAIN)r r.r/r0Zbuilt_in_chainsrCrrr_check_builtin_chains"     z#FirewallDirect._check_builtin_chaincCsH|r|jj|gj|n*|j|j|t|j|dkrD|j|=dS)Nr)rr(r)remover)r r-r0addrrr_register_chains zFirewallDirect._register_chaincCsV|dkr|j}n|}|jjr.|j|jj|jd|||||dkrR|jddS)NT)rr may_skip_flush_direct_backendsadd_preflush_direct_backends_chainr#)r r.r/r0r$r%rrrr6s  zFirewallDirect.add_chaincCs>|dkr|j}n|}|jd|||||dkr:|jddS)NFT)rrLr#)r r.r/r0r$r%rrr remove_chains  zFirewallDirect.remove_chaincCs:|j|||j|||||f}||jko8||j|kS)N)r@rEr)r r.r/r0r-rrrr's   zFirewallDirect.query_chaincCs,|j||||f}||jkr(|j|SgS)N)r@r)r r.r/r-rrr get_chainss    zFirewallDirect.get_chainscCsDg}x:|jD]0}|\}}x"|j|D]}|j|||fq$Wq W|S)N)rr))r rkeyr.r/r0rrrrs  zFirewallDirect.get_all_chainscCsZ|dkr|j}n|}|jjr.|j|jj|jd|||||||dkrV|jddS)NT)rr rIrJrK_ruler#)r r.r/r0r2r3r$r%rrrr8 s  zFirewallDirect.add_rulecCsB|dkr|j}n|}|jd|||||||dkr>|jddS)NFT)rrQr#)r r.r/r0r2r3r$r%rrr remove_rules  zFirewallDirect.remove_rulecCs2|j|||||f}||jko0||f|j|kS)N)r@r)r r.r/r0r2r3r1rrrr*#s   zFirewallDirect.query_rulecCs6|j|||||f}||jkr2t|j|jSgS)N)r@rlistr?)r r.r/r0r1rrr get_rules)s    zFirewallDirect.get_rulesc CsRg}xH|jD]>}|\}}}x.|j|D] \}}|j||||t|fq&Wq W|S)N)rr)rS)r rOrPr.r/r0r2r3rrrr0s    zFirewallDirect.get_all_rulescCs|rr||jkrt|j|<||j||<||jkrg}x4|jD]*}x$|j|D]}|j|t|fqWq W|S)N)rr)rS)r rOr.r3rrrr {s  z#FirewallDirect.get_all_passthroughscCs4g}||jkr0x |j|D]}|jt|qW|S)N)rr)rS)r r.rOr3rrrget_passthroughss  zFirewallDirect.get_passthroughsc Csg}x|D]}d}x|D]}y|j|}Wntk r>YqXt||krd||dkrd}||djd}x.|D]&} |dd} | | |d<|j| qxWqW|s |j|q W|S)z5Split values combined with commas for options in optsF,TN)index ValueErrorrsplitr)) r r,ZoptsZ out_rulesrYZ processedoptiitemsitemrQrrr split_values$     zFirewallDirect.split_valuec Cs*|j|||jj r2|dkr2|jjj|||||}|jj|} |jj rd| j|||rdd|}n:|jjr|dddkr| j|||ddr|dd}|||f} ||f} |r| |jkr| |j| krtt j d||||fnB| |jks| |j| krtt j d||||f|j| | }d} d } | |j krt |j | j}d }x@|t|kr|||kr| |j | ||7} |d7}qTWt|g}|j|d d g}|j|d d g}x<|D]4}|j| | j|||| t|| d7} | d7} qW|j| | ||| |j|j| | || | dS)Nr;r<z %s_directZ_directz"rule '%s' already is in '%s:%s:%s'zrule '%s' is not in '%s:%s:%s'rdrz-sz--sourcez-dz --destination)r;r<iii)r@r rArDcreate_zone_base_by_chainrBZis_chain_builtinrr rALREADY_ENABLED NOT_ENABLEDrsortedr?rrSrlr8Z build_rulerarXadd_fail)r rVr.r/r0r2r3r%rLbackendr1rUrerWZ positionsjZ args_list_argsrrrrQsZ         (   zFirewallDirect._rulecCs|j|||j|||||f}|rV||jkr||j|krttjd|||fn.||jksn||j|krttjd|||f|jj|}|j ||j ||||j ||||j |j ||| dS)Nz chain '%s' already is in '%s:%s'zchain '%s' is not in '%s:%s') r@rErr rrorpr rBZ add_rulesZbuild_chain_rulesrHrr)r rGr.r/r0r%r-rsrrrrLs$    zFirewallDirect._chainc Cs|j|t|}|rD||jkrp||j|krpttjd||fn,||jks\||j|krpttjd||f|jj|}|r|j ||dkr|j |\}}|r|r|jj j ||||} n |j |} |j|| |j||||j|j||| dS)Nzpassthrough '%s', '%s'r;r<)r;r<)r=rarr rrorpr rBZcheck_passthroughZpassthrough_parse_table_chainrDrnZreverse_passthroughr8r^rr) r rVr.r3r%Z tuple_argsrsr/r0rurrrr_'s0        zFirewallDirect._passthrough)N)N)N)N)N)N)N)N))__name__ __module__ __qualname__rrr rrrrr!r&r4r5r"r=r@rErHr6rMr'rNrr8rRr*rTrrXr]r^r9r`r+r rbrlrQrLr_rrrrr&sL  '       jN)__all__Zfirewall.fw_typesrZ firewall.corerrZfirewall.core.fw_transactionrZfirewall.core.loggerrZfirewallrZfirewall.errorsr objectrrrrrs       PKpge[EL__pycache__/icmp.cpython-36.pycnu[3 g #@sddddgZddddddd d d d d dddddddddddddddddddd d!d"d#d$"Zd%d&d'd(d)dddd*d+d,d,d-d-d.d/d0d0d1d1d2d3Zd4d5Zd6dZd7d8Zd9dZd:S); ICMP_TYPES ICMPV6_TYPEScheck_icmp_typecheck_icmpv6_typez0/0z3/0z3/1z3/2z3/3z3/4z3/5z3/6z3/7z3/9z3/10z3/11z3/12z3/13z3/14z3/15z4/0z5/0z5/1z5/2z5/3z8/0z9/0z10/0z11/0z11/1z12/0z12/1z13/0z14/0z17/0z18/0)"z echo-replypongznetwork-unreachablezhost-unreachablezprotocol-unreachablezport-unreachablezfragmentation-neededzsource-route-failedznetwork-unknownz host-unknownznetwork-prohibitedzhost-prohibitedzTOS-network-unreachablezTOS-host-unreachablezcommunication-prohibitedzhost-precedence-violationzprecedence-cutoffz source-quenchznetwork-redirectz host-redirectzTOS-network-redirectzTOS-host-redirectz echo-requestpingzrouter-advertisementzrouter-solicitationzttl-zero-during-transitzttl-zero-during-reassemblyz ip-header-badzrequired-option-missingztimestamp-requestztimestamp-replyzaddress-mask-requestzaddress-mask-replyz1/0z1/1z1/3z1/4z2/0z4/1z4/2z128/0z129/0z133/0z134/0z135/0z136/0z137/0)zno-routezcommunication-prohibitedzaddress-unreachablezport-unreachablezpacket-too-bigzttl-zero-during-transitzttl-zero-during-reassemblyz bad-headerzunknown-header-typezunknown-optionz echo-requestrz echo-replyrzrouter-solicitationzrouter-advertisementzneighbour-solicitationzneigbour-solicitationzneighbour-advertisementzneigbour-advertisementZredirectcCs|tkr dSdS)NTF)r)_namer/usr/lib/python3.6/icmp.pycheck_icmp_nameVsr cCs|tjkrdSdS)NTF)rvalues)_typerrr r[s cCs|tkr dSdS)NTF)r)rrrr check_icmpv6_name`sr cCs|tjkrdSdS)NTF)rr )r rrr res N)__all__rrr rr rrrrr sxPKpge[x  ,__pycache__/fw_policies.cpython-36.opt-1.pycnu[3 g @sVdgZddlmZddlmZddlmZddlmZddlm Z Gddde Z dS) FirewallPolicies)config)log)LockdownWhitelist)errors) FirewallErrorc@sDeZdZddZddZddZddZd d Zd d Zd dZ dS)rcCsd|_ttj|_dS)NF) _lockdownrrZLOCKDOWN_WHITELISTlockdown_whitelist)selfr !/usr/lib/python3.6/fw_policies.py__init__szFirewallPolicies.__init__cCsd|j|j|jfS)Nz %s(%r, %r)) __class__rr )r r r r __repr__#s zFirewallPolicies.__repr__cCsd|_|jjdS)NF)rr cleanup)r r r r r'szFirewallPolicies.cleanupcCs|dkr2tjd||jj|rtjddSn|dkrdtjd||jj|rtjddSnb|dkrtjd ||jj|rtjd dSn0|d krtjd ||jj|rtjd dSdS)Ncontextz#Doing access check for context "%s"zcontext matches.TZuidzDoing access check for uid %dz uid matches.userz Doing access check for user "%s"z user matches.Zcommandz#Doing access check for command "%s"zcommand matches.F)rZdebug2r Z match_contextZdebug3Z match_uidZ match_userZ match_command)r keyvaluer r r access_check-s*        zFirewallPolicies.access_checkcCs|jrttjdd|_dS)Nzenable_lockdown()T)rrrZALREADY_ENABLED)r r r r enable_lockdownDs z FirewallPolicies.enable_lockdowncCs|jsttjdd|_dS)Nzdisable_lockdown()F)rrrZ NOT_ENABLED)r r r r disable_lockdownIs z!FirewallPolicies.disable_lockdowncCs|jS)N)r)r r r r query_lockdownNszFirewallPolicies.query_lockdownN) __name__ __module__ __qualname__r rrrrrrr r r r rsN) __all__ZfirewallrZfirewall.core.loggerrZ#firewall.core.io.lockdown_whitelistrrZfirewall.errorsrobjectrr r r r s      PKpge[_X|j |q>W|s|jj ||} | r| \} }| rtj||ri} xH|D]@}g| |<x2t||D]"} | |j |jj|j| qWqWxb| D]Z}y|jj|| |Wn<tk r}ztjt j tj |WYdd}~XnXq0Wxh|jD]^\} }y | |WnFtk r}z(tjt j tj d| ||fWYdd}~XnXqWttj||jdS)Nz%s.execute(%s)FTz#Calling fail func %s(%s) failed: %s)rr%r&r-prerr Exceptiondebug1 traceback format_excerrorrZhandle_modulesr'r(r)r rrZCOMMAND_FAILEDpost)r r+rr r4ZerrorMsgdoner,msgZ module_returnZstatusZ undo_rulesrrrr r rexecutefsV    " & zFirewallTransaction.executecCs|tjdt|xd|jD]Z\}}y ||Wqtk rr}z(tjtjtjd|||fWYdd}~XqXqWdS)Nz%s.pre()z"Calling pre func %s(%s) failed: %s) rr%r&rr0r1r2r3r4)r rrr7r r rr/s zFirewallTransaction.precCs|tjdt|xd|jD]Z\}}y ||Wqtk rr}z(tjtjtjd|||fWYdd}~XqXqWdS)Nz %s.post()z#Calling post func %s(%s) failed: %s) rr%r&r r0r1r2r3r4)r rrr7r r rr5s zFirewallTransaction.postN)__name__ __module__ __qualname__rrrrrrrrrr!r"r#r$r-r8r/r5r r r rr s"@ ) __doc____all__r2Zfirewall.core.loggerrZfirewallrZfirewall.errorsrobjectrr r r rs    PKpge[|}RR(__pycache__/fw_zone.cpython-36.opt-1.pycnu[3 gy@sddlZddlZddlmZmZmZddlmZddlm Z ddl m Z ddl m Z mZmZmZmZmZmZmZmZddlmZmZmZddlmZdd lmZdd lmZGd d d e Z!dS) N) SHORTCUTSDEFAULT_ZONE_TARGETSOURCE_IPSET_TYPES)FirewallTransaction)Policy)log) Rich_Service Rich_Port Rich_ProtocolRich_SourcePortRich_ForwardPortRich_IcmpBlock Rich_IcmpTypeRich_Masquerade Rich_Mark) checkIPnMask checkIP6nMask check_mac)errors) FirewallError)LastUpdatedOrderedDictc@sNeZdZdZddZddZddZdd Zd d Zd d Z ddZ ddZ ddZ ddZ ddZddZddZddZddd Zd!d"Zd#d$Zd%d&Zdd'd(Zd)d*Zd+d,Zd-d.Zdd/d0Zdd1d2Zd3d4Zd5d6Zd7d8Zd9d:Zd;d<Z d=d>Z!dd@dAZ"dBdCZ#ddDdEZ$ddFdGZ%ddHdIZ&dJdKZ'dLdMZ(dNdOZ)ddQdRZ*ddSdTZ+ddUdVZ,dWdXZ-ddYdZZ.dd[d\Z/d]d^Z0d_d`Z1dadbZ2ddcddZ3dedfZ4dgdhZ5didjZ6dkdlZ7dmdnZ8dodpZ9ddqdrZ:dsdtZ;dudvZd{d|Z?d}d~Z@ddZAdddZBddZCddZDddZEddZFdddZGddZHddZIddZJdddZKddZLddZMddZNdddZOddZPddZQdddZRdddZSdddZTddZUdddZVddZWddZXddZYdddZZddZ[ddZ\ddZ]ddZ^ddZ_dddZ`ddZaddd„ZbddĄZcddƄZddS) FirewallZonercCs||_i|_i|_dS)N)_fw_zones_zone_policies)selffwr/usr/lib/python3.6/fw_zone.py__init__&szFirewallZone.__init__cCsd|j|jfS)Nz%s(%r)) __class__r)rrrr__repr__+szFirewallZone.__repr__cCs|jj|jjdS)N)rclearr)rrrrcleanup.s zFirewallZone.cleanupcCs t|jS)N)rr)rrrrnew_transaction2szFirewallZone.new_transactioncCsdj||dS)Nzzone_{fromZone}_{toZone})fromZonetoZone)format)rr%r&rrrpolicy_name_from_zones5sz#FirewallZone.policy_name_from_zonescCst|jjS)N)sortedrkeys)rrrr get_zones:szFirewallZone.get_zonescCs8g}x.|jD]"}|j|s&|j|r|j|qW|S)N)r+list_interfaces list_sourcesappend)rZ active_zoneszonerrrget_active_zones=s zFirewallZone.get_active_zonescCs6|j|}x&|jD]}||j|jdkr|SqWdS)N interfaces)_FirewallZone__interface_idrsettings)r interface interface_idr/rrrget_zone_of_interfaceDs   z"FirewallZone.get_zone_of_interfacecCs6|j|}x&|jD]}||j|jdkr|SqWdS)Nsources)_FirewallZone__source_idrr3)rsource source_idr/rrrget_zone_of_sourceLs   zFirewallZone.get_zone_of_sourcecCs|jj|}|j|S)N)r check_zoner)rr/zrrrget_zoneTs zFirewallZone.get_zonecCsBt}|j|_|j|||_|j|_|j|_|g|_|g|_xd D]}||jkr~|d kr~|d kr~t ||t j t ||qD|d kr||jkr|d krt ||t j t ||qD||jko|d ko|dkrt ||t j t ||qD|dkrDg|_ xB|j D]8}|j||}||j|j|kr|j jt j |qWqDW|S)Nservicesports masquerade forward_ports source_ports icmp_blocksrules protocolsHOSTANY)r?r@rArBrCrDrErF)r?r@rCrDrF)rA)rDrB)rE)rnameZderived_from_zoner(ZONE_POLICY_PRIORITYZprioritytargetZ ingress_zonesZ egress_zonessetattrcopydeepcopygetattrrE_rich_rule_to_policiesr.)rz_objr%r&p_objZsettingruleZcurrent_policyrrrpolicy_obj_from_zone_objXs6    z%FirewallZone.policy_obj_from_zone_objcCsddd D|_||j|j<g|j|j<xX|jdfd|jf|jdfgD]8\}}|j|||}|jjj||j|jj|jqFW|j |jdS) NcSsi|] }t|qSr)r).0xrrr sz)FirewallZone.add_zone..r1r7icmp_block_inversionforwardrGrH)r1r7rXrY) r3rrIrrTrpolicyZ add_policyr.copy_permanent_to_runtime)robjr%r&rRrrradd_zone~s   zFirewallZone.add_zonecCsn|j|}x|jD]}|j||ddqWx|jD]}|j||ddq2W|jrZ|j||jrj|j|dS)NF) allow_apply) rr1 add_interfacer7 add_sourcerY add_forwardrXadd_icmp_block_inversion)rr/r\argrrrr[s    z&FirewallZone.copy_permanent_to_runtimecCs8|j|}|jr|j||jj|j|=|j|=dS)N)rappliedunapply_zone_settingsr3r"r)rr/r\rrr remove_zones    zFirewallZone.remove_zoneNcCsVxP|jD]D}|j|}t|jdks4t|jdkr tjd||j||dq WdS)NrzApplying zone '%s')use_transaction)r+rlenr1r7rdebug1apply_zone_settings)rrgr/rQrrr apply_zoness   zFirewallZone.apply_zonescCs|j|}||_dS)N)rrd)rr/rdr\rrrset_zone_applieds zFirewallZone.set_zone_appliedcCsd|kr dS|jd}t|dkr&dSd}x tD]}|dt|kr0|}q0W|dk r|d|jkrhdSt|dkst|dkr|dd kr|d|fSdS) N_rprerdenyallowpost)rqrrrrsrt)splitrhrr+)rchainZsplits_chainrVrrrzone_from_chains      zFirewallZone.zone_from_chaincCst|j|}|dkrdS|\}}|d kr0|}d}n4|d krB|}d}n"|d krTd}|}nttjd||j|||fS) N PREROUTING FORWARD_INrHINPUTrG POSTROUTING FORWARD_OUTz&chain '%s' can't be mapped to a policy)ryrz)r{)r|r})rxrrZ INVALID_CHAINr()rrvrVr/rwr%r&rrrpolicy_from_chains zFirewallZone.policy_from_chainc Csj|dkrf|j|}|dk rf|j|\}}|dkr:|j}n|}|jjj|d||||dkrf|jddS)Nipv4ipv6T)rr)r~r$rrZZgen_chain_rulesexecute) ripvtablervrgrVrZrw transactionrrrcreate_zone_base_by_chains  z&FirewallZone.create_zone_base_by_chaincCstj||d}|S)N)Zdatesendertimeout)time)rrrretrrrZ__gen_settingsszFirewallZone.__gen_settingscCs |j|jS)N)r>r3)rr/rrr get_settingsszFirewallZone.get_settingscCs|j|}x|D]z}xt||D]h}|dkr<|j||||q|dkr`|j|||d|d|q|dkrlqq|dkrvqtjd|||qWqW|r|j|||dS)Nr1r7rrorXrYz3Zone '%s': Unknown setting '%s:%s', unable to apply)r _interface_sourcerZwarning_icmp_block_inversion)renabler/rr3keyargsrrr_zone_settingss  zFirewallZone._zone_settingscCs|jj|}|j|}|jr dSd|_|dkr8|j}n|}x2|j|D]$}tjd|||jjj ||dqHW|j d|||dkr|j ddS)NTz+Applying policy (%s) derived from zone '%s')rg) rr<rrdr$rrrirZapply_policy_settingsrr)rr/rg_zoner\rrZrrrrjs   z FirewallZone.apply_zone_settingscCs|jj|}|j|}|js dS|dkr2|j}n|}x$|j|D]}|jjj||dqBW|jd|||dkr||j ddS)N)rgFT) rr<rrdr$rrZunapply_policy_settingsrr)rr/rgrr\rrZrrrre,s   z"FirewallZone.unapply_zone_settingscCs~|j|}|j|}g}x\tdD]P}|j|d|krZ|jtjt||j|dq"|j||j|dq"Wt|S)zH :return: exported config updated with runtime settings r) r>get_config_with_settings_dictrangeZIMPORT_EXPORT_STRUCTUREr.rMrNrOtuple)rr/r\Z conf_dictZ conf_listirrrget_config_with_settings?s  "z%FirewallZone.get_config_with_settingsc Cs|j|j}|dtkr"d|d<|j||j||j||j||j||j||j ||j ||j ||j ||j ||j|d }|jj||S)zH :return: exported config updated with runtime settings rKdefault) r?r@rDrArBr1r7 rules_strrFrCrXrY)r>Zexport_config_dictr list_services list_portslist_icmp_blocksquery_masqueradelist_forward_portsr,r- list_ruleslist_protocolslist_source_portsquery_icmp_block_inversion query_forwardrZ'combine_runtime_with_permanent_settings)rr/Z permanentZruntimerrrrOs  z*FirewallZone.get_config_with_settings_dictc sddlmdfdd }fdd}jjfjjfjjfjj fj j fj j fjjf||fjjfjjfjjfjjfd }j|}jj||\}} xv| D]n} t| | tr$xX| | D]:} t| tr || d|f| q|| d|| qWq|| d|qWx|D]} t|| trx|| D]l} | dkr|| d|| |d nDt| tr|| d|f| d|d n|| d|| d|d q\Wn6| dkr|| d||d n|| d|d|d q>WdS)Nr) Rich_Rulecsj||dd|ddS)N)rule_strr)rr)add_rule)r/rrr)rrrradd_rule_wrapperhszDFirewallZone.set_config_with_settings_dict..add_rule_wrappercsj||ddS)N)r) remove_rule)r/r)rrrrremove_rule_wrapperjszGFirewallZone.set_config_with_settings_dict..remove_rule_wrapper) r?r@rDrArBr1r7rrFrCrXrYror1r7)r)rrrX)rN)r1r7)rX)firewall.core.richr add_serviceremove_serviceadd_port remove_portadd_icmp_blockremove_icmp_blockadd_masqueraderemove_masqueradeadd_forward_portremove_forward_portr_remove_interfacer` remove_source add_protocolremove_protocoladd_source_portremove_source_portrbremove_icmp_block_inversionraremove_forwardrrZget_added_and_removed_settings isinstancelistr) rr/r3rrrZ setting_to_fnZ old_settingsZ add_settingsZremove_settingsrrr)rrrset_config_with_settings_dictesF                    z*FirewallZone.set_config_with_settings_dictcCs|jj|dS)N)rcheck_interface)rr4rrrrszFirewallZone.check_interfacecCs\|jj|}|j|}|j|}||jdkrX|jd|}d|krX|ddk rX|dSdS)Nr1r)rr<rr2r3)rr/r4r_objr5r3rrrinterface_get_senders   z!FirewallZone.interface_get_sendercCs|j||S)N)r)rr4rrrZ__interface_ids zFirewallZone.__interface_idTc Cs|jj|jj|}|j|}|j|}||jdkrLttjd||f|j |dk rjttj d|t j d||f|dkr|j } n|} |j r|r|j|| d| j|j|d|r|jd||| |j||||| j|j|||dkr| jd|S)Nr1z'%s' already bound to '%s'z'%s' already bound to a zonez&Setting zone of interface '%s' to '%s')rgFT)r check_panicr<rr2r3rrZONE_ALREADY_SETr6 ZONE_CONFLICTrrir$rdrjadd_failrlr!_FirewallZone__register_interface#_FirewallZone__unregister_interfacer) rr/r4rrgr^rrr5rrrrr_s8            zFirewallZone.add_interfacecCs6|jd||jd|<| p"|dk|jd|d<dS)Nrr1 __default__)_FirewallZone__gen_settingsr3)rrr5r/rrrrZ__register_interfacesz!FirewallZone.__register_interfacecCsR|jj|j|}|jj|}||kr,|S|dk r@|j|||j|||}|S)N)rrr6r<rr_)rr/r4r _old_zone _new_zonerrrrchange_zone_of_interfaces    z%FirewallZone.change_zone_of_interfacecCsz|jj|dkr|j}n|}|j|||jd|d|dd|dk rd|dkrd|jd|d|dd|dkrv|jddS)NT+)r.rF)rrr$rjrr)rZold_zoneZnew_zonergrrrrchange_default_zones   z FirewallZone.change_default_zonec Cs|jj|j|}|dkr,ttjd||dkr8|n |jj|}||krbttjd|||f|dkrt|j}n|}|j |}|j |}|j |j |||j d||||dkr|jd|S)Nz'%s' is not in any zonerz"remove_interface(%s, %s): zoi='%s'FT)rrr6rrZUNKNOWN_INTERFACEr<rr$rr2add_postrrr) rr/r4rgZzoirrrr5rrrrs(       zFirewallZone.remove_interfacecCs||jdkr|jd|=dS)Nr1)r3)rrr5rrrZ__unregister_interfacesz#FirewallZone.__unregister_interfacecCs|j||j|dkS)Nr1)r2r)rr/r4rrrquery_interfaceszFirewallZone.query_interfacecCs|j|djS)Nr1)rr*)rr/rrrr,"szFirewallZone.list_interfacesFcCsxt|r dSt|rdSt|r$dS|jdrh|j|dd|rV|j|dd|j|ddSttj |dS)Nrrrzipset:) rrr startswith_check_ipset_type_for_source_check_ipset_applied _ipset_familyrrZ INVALID_ADDR)rr9rdrrr check_source's zFirewallZone.check_sourcecCs|j||d}||fS)N)rd)r)rr9rdrrrrZ __source_id6szFirewallZone.__source_idc Cs|jj|jj|}|j|}t|r0|j}|j||d}||jdkr`tt j d||f|j |dk r~tt j d||dkr|j } n|} |j r|r|j|| d| j|j|d|r|jd||d|d | |j||||| j|j|||dkr| jd|S) N)rdr7z'%s' already bound to '%s'z'%s' already bound to a zone)rgFTrro)rrr<rrupperr8r3rrrr;rr$rdrjrrlr_FirewallZone__register_source _FirewallZone__unregister_sourcer) rr/r9rrgr^rrr:rrrrr`:s4        zFirewallZone.add_sourcecCs6|jd||jd|<| p"|dk|jd|d<dS)Nrr7rr)rr3)rrr:r/rrrrZ__register_sourceaszFirewallZone.__register_sourcecCsb|jj|j|}|jj|}||kr,|St|r<|j}|dk rP|j|||j|||}|S)N)rrr;r<rrrr`)rr/r9rrrrrrrchange_zone_of_sourcegs    z"FirewallZone.change_zone_of_sourcec Cs|jjt|r|j}|j|}|dkrsz-FirewallZone.list_sources..r7)rr*)rr/rrrr-szFirewallZone.list_sourcesc sxjjD]}|jsq xPj|D]B}x<jjj|D]*\}} |j|||||| |} |j|| q8Wq$Wj|d}j |dr |d kr |j |||d|d} |j|| q WxΈjjj D]}|jjj |kr|jjj |krq|jjjkrdjjj|jrd| rsz)FirewallZone._interface..cs|jjjkojjj|S)N)rrZrr)r)rrrrs)rr)renabled_backendspolicies_supportedrrZ#_get_table_chains_for_zone_dispatchZ!build_zone_source_interface_rules add_rulesr(rbuild_zone_forward_rules"get_policies_not_derived_from_zonelist_ingress_zoneslist_egress_zonesr get_policyrdrhr,r_ingress_egress_zonesr) rrr/r4rr.backendrZrrvrEr)rrrs2 $zFirewallZone._interfacecCs$|j|dkrdS|jjj|ddS)Nzhash:macF)rd) _ipset_typeripsetZ get_family)rrIrrrrszFirewallZone._ipset_familycCs|jjj|ddS)NF)rd)rrZget_type)rrIrrrrszFirewallZone._ipset_typecCsdj|g|jjj|S)N,)joinrrZ get_dimension)rrIflagrrr_ipset_match_flagsszFirewallZone._ipset_match_flagscCs|jjj|S)N)rrZ check_applied)rrIrrrrsz!FirewallZone._check_ipset_appliedcCs*|j|}|tkr&ttjd||fdS)Nz.ipset '%s' with type '%s' not usable as source)rrrrZ INVALID_IPSET)rrIZ_typerrrrs  z)FirewallZone._check_ipset_type_for_sourcec sx|rjj|gnjjD]}|js*qxNj|D]@}x:jjj|D](\}} |j|||||| } |j|| qJWq6Wj |d}j |dr|j |||d|d} |j|| qWxΈjjj D]}|jjj |kr|jjj|krq|jjjkrljjj|jrl| rDtj|dkrDjjj||dn&jjjd|||jfdd |q|r|jfd d |qWdS) NrHrYr)r9ro)rgFcs |jjjkojjjd|S)NT)rrZrr)r)rrrrsz&FirewallZone._source..cs|jjjkojjj|S)N)rrZrr)r)rrrr s)rget_backend_by_ipvrrrrZrZbuild_zone_source_address_rulesrr(rrrrrrrrdrhr-rrr) rrr/rr9rrrZrrvrEr)rrrs2"  $zFirewallZone._sourcecCs0|jj|}|j|d}|jjj|||||S)NrG)rr<r(rZr)rr/servicerrp_namerrrr s  zFirewallZone.add_servicecCs,|jj|}|j|d}|jjj|||S)NrG)rr<r(rZr)rr/rrrrrrs  zFirewallZone.remove_servicecCs(|jj|}|j|d}|jjj||S)NrG)rr<r(rZ query_service)rr/rrrrrrs  zFirewallZone.query_servicecCs&|jj|}|j|d}|jjj|S)NrG)rr<r(rZr)rr/rrrrrs  zFirewallZone.list_servicescCs2|jj|}|j|d}|jjj||||||S)NrG)rr<r(rZr)rr/portprotocolrrrrrrr#s  zFirewallZone.add_portcCs.|jj|}|j|d}|jjj||||S)NrG)rr<r(rZr)rr/rrrrrrr)s  zFirewallZone.remove_portcCs*|jj|}|j|d}|jjj|||S)NrG)rr<r(rZ query_port)rr/rrrrrrr/s  zFirewallZone.query_portcCs&|jj|}|j|d}|jjj|S)NrG)rr<r(rZr)rr/rrrrr4s  zFirewallZone.list_portscCs2|jj|}|j|d}|jjj||||||S)NrG)rr<r(rZr)rr/ source_portrrrrrrrr9s  zFirewallZone.add_source_portcCs.|jj|}|j|d}|jjj||||S)NrG)rr<r(rZr)rr/rrrrrrr?s  zFirewallZone.remove_source_portcCs*|jj|}|j|d}|jjj|||S)NrG)rr<r(rZquery_source_port)rr/rrrrrrrEs  zFirewallZone.query_source_portcCs&|jj|}|j|d}|jjj|S)NrG)rr<r(rZr)rr/rrrrrJs  zFirewallZone.list_source_portscCs|jj|}t|jtkr(|j|dgSt|jttt t gkrL|j|dgSt|jt t gkrv|j|d|j|dgSt|jt gkr|j|dgSt|jtgkr|jd|gS|jdkr|j|dgStdt|jdS)NrHrGz Rich rule type (%s) not handled.)rr<typeactionrr(elementrr r r r rr rr)rr/rSrrrrPOs    z#FirewallZone._rich_rule_to_policiescCs.x(|j||D]}|jjj||||qW|S)N)rPrrZr)rr/rSrrrrrrrbszFirewallZone.add_rulecCs*x$|j||D]}|jjj||qW|S)N)rPrrZr)rr/rSrrrrrgszFirewallZone.remove_rulecCs2d}x(|j||D]}|o(|jjj||}qW|S)NT)rPrrZ query_rule)rr/rSrrrrrrlszFirewallZone.query_rulecCs^|jj|}t}xB|j|d|j|d|jd|gD]}|jt|jjj|q6Wt|S)NrHrG)rr<setr(updaterZrr)rr/rrrrrrrs   zFirewallZone.list_rulescCs0|jj|}|j|d}|jjj|||||S)NrG)rr<r(rZr)rr/rrrrrrrr{s  zFirewallZone.add_protocolcCs,|jj|}|j|d}|jjj|||S)NrG)rr<r(rZr)rr/rrrrrrs  zFirewallZone.remove_protocolcCs(|jj|}|j|d}|jjj||S)NrG)rr<r(rZquery_protocol)rr/rrrrrr s  zFirewallZone.query_protocolcCs&|jj|}|j|d}|jjj|S)NrG)rr<r(rZr)rr/rrrrrs  zFirewallZone.list_protocolscCs.|jj|}|jd|}|jjj||||S)NrH)rr<r(rZr)rr/rrrrrrrs  zFirewallZone.add_masqueradecCs*|jj|}|jd|}|jjj||S)NrH)rr<r(rZr)rr/rrrrrs  zFirewallZone.remove_masqueradecCs&|jj|}|jd|}|jjj|S)NrH)rr<r(rZr)rr/rrrrrs  zFirewallZone.query_masqueradec Cs6|jj|}|j|d}|jjj||||||||S)NrH)rr<r(rZr) rr/rrtoporttoaddrrrrrrrrs   zFirewallZone.add_forward_portcCs2|jj|}|j|d}|jjj||||||S)NrH)rr<r(rZr)rr/rrr r rrrrrs  z FirewallZone.remove_forward_portcCs.|jj|}|j|d}|jjj|||||S)NrH)rr<r(rZquery_forward_port)rr/rrr r rrrrr s  zFirewallZone.query_forward_portcCs&|jj|}|j|d}|jjj|S)NrH)rr<r(rZr)rr/rrrrrs  zFirewallZone.list_forward_portscCsP|jj|}|j|d}|jjj|||||j|d}|jjj|||||S)NrGrH)rr<r(rZr)rr/icmprrrrrrrs    zFirewallZone.add_icmp_blockcCsH|jj|}|j|d}|jjj|||j|d}|jjj|||S)NrGrH)rr<r(rZr)rr/r rrrrrs    zFirewallZone.remove_icmp_blockcCsD|jj|}|j|d}|j|d}|jjj||oB|jjj||S)NrGrH)rr<r(rZquery_icmp_block)rr/r  p_name_host p_name_fwdrrrrs    zFirewallZone.query_icmp_blockcCsH|jj|}|j|d}|j|d}tt|jjj||jjj|S)NrGrH)rr<r(r)rrZr)rr/rrrrrrs    zFirewallZone.list_icmp_blockscCsH|jj|}|j|d}|jjj|||j|d}|jjj|||S)NrGrH)rr<r(rZrb)rr/rrrrrrbs    z%FirewallZone.add_icmp_block_inversioncCsL|jj|}|j|d}|jjj||||j|d}|jjj|||dS)NrGrH)rr<r(rZr)rrr/rrrrrrs    z"FirewallZone._icmp_block_inversioncCsD|jj|}|j|d}|jjj||j|d}|jjj||S)NrGrH)rr<r(rZr)rr/rrrrrs    z(FirewallZone.remove_icmp_block_inversioncCs@|jj|}|j|d}|j|d}|jjj|o>|jjj|S)NrGrH)rr<r(rZr)rr/rrrrrrs    z'FirewallZone.query_icmp_block_inversionc Cs|j|d}xT|j|jdD]@}x:|jjD],}|js:q.|j|||d|d}|j||q.WqWxj|j|jdD]V\}} xL|r|jj|gn|jjD],}|jsq|j|||d| d}|j||qWqtWdS)NrHr1r)r4r7)r9) r(rr3rrrrrr) rrr/rrr4rrErr9rrr_forwards "zFirewallZone._forwardcCsdS)NTr)rrrrZ __forward_idszFirewallZone.__forward_idc Cs|jj|}|jj||jj|j|}|j}||jdkrRttj d||dkrd|j }n|}|j r||j d|||j |||||j|j|||dkr|jd|S)NrYzforward already enabled in '%s'T)rr<Z check_timeoutrr_FirewallZone__forward_idr3rrZALREADY_ENABLEDr$rdr_FirewallZone__register_forwardr!_FirewallZone__unregister_forwardr) rr/rrrgrr forward_idrrrrras$       zFirewallZone.add_forwardcCs|j|||jd|<dS)NrY)rr3)rrrrrrrrZ__register_forward.szFirewallZone.__register_forwardcCs|jj|}|jj|j|}|j}||jdkrFttjd||dkrX|j }n|}|j rp|j d|||j |j |||dkr|jd|S)NrYzforward not enabled in '%s'FT)rr<rrrr3rrZ NOT_ENABLEDr$rdrrrr)rr/rgrrrrrrrr2s       zFirewallZone.remove_forwardcCs||jdkr|jd|=dS)NrY)r3)rrrrrrZ__unregister_forwardKsz!FirewallZone.__unregister_forwardcCs|j|j|dkS)NrY)rr)rr/rrrrOszFirewallZone.query_forward)N)N)N)N)NNT)N)N)N)F)F)NNT)N)N)F)rN)rN)rN)rN)rN)rN)NNrN)NN)NN)rN)N)rNN)N)e__name__ __module__ __qualname__rJrr!r#r$r(r+r0r6r;r>rTr]r[rfrkrlrxr~rrrrrjrerrrrrr2r_rrrrrrr,rr8r`rrrrrr-rrrrrrrrrrrrrrrrrrrrPrrrrrrr rrrrrrr rrrrrrbrrrrrrarrrrrrrrr#s&     8  (      &   ,(               r)"rrMZfirewall.core.baserrrZfirewall.core.fw_transactionrZfirewall.core.io.policyrZfirewall.core.loggerrrrr r r r r rrrZfirewall.functionsrrrZfirewallrZfirewall.errorsrZfirewall.fw_typesrobjectrrrrrs   ,   PKpge[ Dm ,__pycache__/fw_icmptype.cpython-36.opt-1.pycnu[3 g @s>dgZddlmZddlmZddlmZGdddeZdS)FirewallIcmpType)log)errors) FirewallErrorc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)rcCs||_i|_dS)N)_fw _icmptypes)selffwr !/usr/lib/python3.6/fw_icmptype.py__init__szFirewallIcmpType.__init__cCsd|j|jfS)Nz%s(%r)) __class__r)rr r r __repr__!szFirewallIcmpType.__repr__cCs|jjdS)N)rclear)rr r r cleanup$szFirewallIcmpType.cleanupcCst|jjS)N)sortedrkeys)rr r r get_icmptypes)szFirewallIcmpType.get_icmptypescCs||jkrttj|dS)N)rrrZINVALID_ICMPTYPE)ricmptyper r r check_icmptype,s zFirewallIcmpType.check_icmptypecCs|j||j|S)N)rr)rrr r r get_icmptype0s zFirewallIcmpType.get_icmptypecCs|j}t|dkrddg}x|D]z}|dkrL|jj rB|jj rBq |jj}n,|dkrt|jj rj|jj rjq |jj}ng}|jj |kr t j d|j|fq W||j |j<dS)NrZipv4Zipv6z5ICMP type '%s' is not supported by the kernel for %s.) Z destinationlenrZip4tables_enabledZnftables_enabledZipv4_supported_icmp_typesZip6tables_enabledZipv6_supported_icmp_typesnamelowerrZinfo1r)robjZ orig_ipvsZipvZsupported_icmpsr r r add_icmptype4s     zFirewallIcmpType.add_icmptypecCs|j||j|=dS)N)rr)rrr r r remove_icmptypeGs z FirewallIcmpType.remove_icmptypeN) __name__ __module__ __qualname__r rrrrrrrr r r r rsN) __all__Zfirewall.core.loggerrZfirewallrZfirewall.errorsrobjectrr r r r s   PKpge[ = (__pycache__/watcher.cpython-36.opt-1.pycnu[3 g @s*dgZddlmZmZGdddeZdS)Watcher)GioGLibc@sdeZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ dS)rcCs"||_||_i|_i|_g|_dS)N) _callback_timeout _monitors _timeouts_blocked)selfcallbackZtimeoutr /usr/lib/python3.6/watcher.py__init__s zWatcher.__init__cCs:tjj|}|jtjjd|j|<|j|jd|jdS)Nchanged) rFile new_for_pathZmonitor_directoryFileMonitorFlagsNONErconnect_file_changed_cb)r Z directorygfiler r r add_watch_dir"s zWatcher.add_watch_dircCs:tjj|}|jtjjd|j|<|j|jd|jdS)Nr) rrrZ monitor_filerrrrr)r filenamerr r r add_watch_file(s zWatcher.add_watch_filecCs |jjS)N)rkeys)r r r r get_watches.szWatcher.get_watchescCs ||jkS)N)r)r rr r r has_watch1szWatcher.has_watchcCs |j|=dS)N)r)r rr r r remove_watch4szWatcher.remove_watchcCs||jkr|jj|dS)N)r append)r rr r r block_source7s zWatcher.block_sourcecCs||jkr|jj|dS)N)r remove)r rr r r unblock_source;s zWatcher.unblock_sourcecCs4x.t|jjD]}tj|j||j|=qWdS)N)listrrr source_remove)r rr r r clear_timeouts?szWatcher.clear_timeoutscCs ||jkr|j||j|=dS)N)r rr)r rr r r _call_callbackDs  zWatcher._call_callbackcCs|j}||jkr8||jkr4tj|j||j|=dS|tjjksh|tjjksh|tjj ksh|tjj kr||jkrtj|j||j|=tj |j |j ||j|<dS)N)Zget_parse_namer rrr#rZFileMonitorEventZCHANGEDZCREATEDZDELETEDZATTRIBUTE_CHANGEDZtimeout_add_secondsrr%)r ZmonitorZgio_fileZgio_other_fileZeventrr r r rIs       zWatcher._file_changed_cbN)__name__ __module__ __qualname__rrrrrrrr!r$r%rr r r r rsN)__all__Z gi.repositoryrrobjectrr r r r sPKpge[qwט22$__pycache__/fw_direct.cpython-36.pycnu[3 gW@sndgZddlmZddlmZddlmZddlmZddlm Z ddl m Z ddl m Z Gd ddeZd S) FirewallDirect)LastUpdatedOrderedDict) ipXtables)ebtables)FirewallTransaction)log)errors) FirewallErrorc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dNddZ ddZ ddZ dOddZddZddZddZd d!ZdPd"d#ZdQd$d%Zd&d'Zd(d)Zd*d+ZdRd,d-ZdSd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;ZdTdd?Z!d@dAZ"dBdCZ#dDdEZ$dFdGZ%dHdIZ&dJdKZ'dLdMZ(dS)VrcCs||_|jdS)N)_fw_FirewallDirect__init_vars)selffwr/usr/lib/python3.6/fw_direct.py__init__'szFirewallDirect.__init__cCsd|j|j|j|jfS)Nz%s(%r, %r, %r)) __class___chains_rules_rule_priority_positions)r rrr__repr__+szFirewallDirect.__repr__cCs"i|_i|_i|_i|_d|_dS)N)rrr _passthroughs_obj)r rrrZ __init_vars/s zFirewallDirect.__init_varscCs |jdS)N)r )r rrrcleanup6szFirewallDirect.cleanupcCs t|jS)N)rr )r rrrnew_transaction;szFirewallDirect.new_transactioncCs ||_dS)N)r)r objrrrset_permanent_config@sz#FirewallDirect.set_permanent_configcCs*t|jt|jt|jdkr&dSdS)NrTF)lenrrr)r rrrhas_runtime_configurationCs"z(FirewallDirect.has_runtime_configurationcCsB|jr dSt|jjt|jjt|jjdkr>dSdS)NTrF)rrrget_all_chains get_all_rulesget_all_passthroughs)r rrrhas_configurationHs z FirewallDirect.has_configurationNcCsP|dkr|j}n|}|j|jj|jj|jjf||dkrL|jddS)NT)r set_configrrrr execute)r use_transaction transactionrrr apply_directQs   zFirewallDirect.apply_directc Csi}i}i}xL|jD]B}|\}}x4|j|D]&}|jj|||s,|j|gj|q,WqWxf|jD]\}|\}}}xL|j|D]>\} } |jj|||| | s|||krt||<| ||| | f<q|WqbWxP|jD]F}x@|j|D]2} |jj || s||krg||<||j| qWqW|||fS)N) rr query_chain setdefaultappendr query_rulerrquery_passthrough) r ZchainsrulesZ passthroughstable_idipvtablechainchain_idpriorityargsrrrget_runtime_configbs,      z!FirewallDirect.get_runtime_configcCs|j|j|jfS)N)rrr)r rrr get_configszFirewallDirect.get_configcCs|dkr|j}n|}|\}}}x||D]t}|\}} xf||D]Z} |j|| | sr nftables_enabledget_direct_backend_by_ipv our_chainsrZ OUR_CHAINSr rZ BUILTIN_CHAINzoneZzone_from_chainZ INVALID_CHAIN)r r.r/r0Zbuilt_in_chainsrCrrr_check_builtin_chains"     z#FirewallDirect._check_builtin_chaincCsH|r|jj|gj|n*|j|j|t|j|dkrD|j|=dS)Nr)rr(r)remover)r r-r0addrrr_register_chains zFirewallDirect._register_chaincCsV|dkr|j}n|}|jjr.|j|jj|jd|||||dkrR|jddS)NT)rr may_skip_flush_direct_backendsadd_preflush_direct_backends_chainr#)r r.r/r0r$r%rrrr6s  zFirewallDirect.add_chaincCs>|dkr|j}n|}|jd|||||dkr:|jddS)NFT)rrLr#)r r.r/r0r$r%rrr remove_chains  zFirewallDirect.remove_chaincCs:|j|||j|||||f}||jko8||j|kS)N)r@rEr)r r.r/r0r-rrrr's   zFirewallDirect.query_chaincCs,|j||||f}||jkr(|j|SgS)N)r@r)r r.r/r-rrr get_chainss    zFirewallDirect.get_chainscCsDg}x:|jD]0}|\}}x"|j|D]}|j|||fq$Wq W|S)N)rr))r rkeyr.r/r0rrrrs  zFirewallDirect.get_all_chainscCsZ|dkr|j}n|}|jjr.|j|jj|jd|||||||dkrV|jddS)NT)rr rIrJrK_ruler#)r r.r/r0r2r3r$r%rrrr8 s  zFirewallDirect.add_rulecCsB|dkr|j}n|}|jd|||||||dkr>|jddS)NFT)rrQr#)r r.r/r0r2r3r$r%rrr remove_rules  zFirewallDirect.remove_rulecCs2|j|||||f}||jko0||f|j|kS)N)r@r)r r.r/r0r2r3r1rrrr*#s   zFirewallDirect.query_rulecCs6|j|||||f}||jkr2t|j|jSgS)N)r@rlistr?)r r.r/r0r1rrr get_rules)s    zFirewallDirect.get_rulesc CsRg}xH|jD]>}|\}}}x.|j|D] \}}|j||||t|fq&Wq W|S)N)rr)rS)r rOrPr.r/r0r2r3rrrr0s    zFirewallDirect.get_all_rulescCs|rr||jkrt|j|<||j||<||jkrg}x4|jD]*}x$|j|D]}|j|t|fqWq W|S)N)rr)rS)r rOr.r3rrrr {s  z#FirewallDirect.get_all_passthroughscCs4g}||jkr0x |j|D]}|jt|qW|S)N)rr)rS)r r.rOr3rrrget_passthroughss  zFirewallDirect.get_passthroughsc Csg}x|D]}d}x|D]}y|j|}Wntk r>YqXt||krd||dkrd}||djd}x.|D]&} |dd} | | |d<|j| qxWqW|s |j|q W|S)z5Split values combined with commas for options in optsF,TN)index ValueErrorrsplitr)) r r,ZoptsZ out_rulesrYZ processedoptiitemsitemrQrrr split_values$     zFirewallDirect.split_valuec Cs*|j|||jj r2|dkr2|jjj|||||}|jj|} |jj rd| j|||rdd|}n:|jjr|dddkr| j|||ddr|dd}|||f} ||f} |r| |jkr| |j| krtt j d||||fnB| |jks| |j| krtt j d||||f|j| | }d} d } | |j krt |j | j}d }x@|t|kr|||kr| |j | ||7} |d7}qTWt|g}|j|d d g}|j|d d g}x<|D]4}|j| | j|||| t|| d7} | d7} qW|j| | ||| |j|j| | || | dS)Nr;r<z %s_directZ_directz"rule '%s' already is in '%s:%s:%s'zrule '%s' is not in '%s:%s:%s'rdrz-sz--sourcez-dz --destination)r;r<iii)r@r rArDcreate_zone_base_by_chainrBZis_chain_builtinrr rALREADY_ENABLED NOT_ENABLEDrsortedr?rrSrlr8Z build_rulerarXadd_fail)r rVr.r/r0r2r3r%rLbackendr1rUrerWZ positionsjZ args_list_argsrrrrQsZ         (   zFirewallDirect._rulecCs|j|||j|||||f}|rV||jkr||j|krttjd|||fn.||jksn||j|krttjd|||f|jj|}|j ||j ||||j ||||j |j ||| dS)Nz chain '%s' already is in '%s:%s'zchain '%s' is not in '%s:%s') r@rErr rrorpr rBZ add_rulesZbuild_chain_rulesrHrr)r rGr.r/r0r%r-rsrrrrLs$    zFirewallDirect._chainc Cs|j|t|}|rD||jkrp||j|krpttjd||fn,||jks\||j|krpttjd||f|jj|}|r|j ||dkr|j |\}}|r|r|jj j ||||} n |j |} |j|| |j||||j|j||| dS)Nzpassthrough '%s', '%s'r;r<)r;r<)r=rarr rrorpr rBZcheck_passthroughZpassthrough_parse_table_chainrDrnZreverse_passthroughr8r^rr) r rVr.r3r%Z tuple_argsrsr/r0rurrrr_'s0        zFirewallDirect._passthrough)N)N)N)N)N)N)N)N))__name__ __module__ __qualname__rrr rrrrr!r&r4r5r"r=r@rErHr6rMr'rNrr8rRr*rTrrXr]r^r9r`r+r rbrlrQrLr_rrrrr&sL  '       jN)__all__Zfirewall.fw_typesrZ firewall.corerrZfirewall.core.fw_transactionrZfirewall.core.loggerrZfirewallrZfirewall.errorsr objectrrrrrs       PKpge[*__pycache__/fw_helper.cpython-36.opt-1.pycnu[3 g)@s6dZdgZddlmZddlmZGdddeZdS)zhelper backendFirewallHelper)errors) FirewallErrorc@s\eZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ dS)rcCs||_i|_dS)N)Z_fw_helpers)selffwr/usr/lib/python3.6/fw_helper.py__init__szFirewallHelper.__init__cCsd|j|jfS)Nz%s(%r)) __class__r)rrrr __repr__"szFirewallHelper.__repr__cCs|jjdS)N)rclear)rrrr cleanup'szFirewallHelper.cleanupcCs||jkrttj|dS)N) get_helpersrrINVALID_HELPER)rnamerrr check_helper*s zFirewallHelper.check_helpercCs ||jkS)N)r)rrrrr query_helper.szFirewallHelper.query_helpercCst|jjS)N)sortedrkeys)rrrr r1szFirewallHelper.get_helperscCst|jdkS)Nr)lenr)rrrr has_helpers4szFirewallHelper.has_helperscCs|j||j|S)N)rr)rrrrr get_helper7s zFirewallHelper.get_helpercCs||j|j<dS)N)rr)robjrrr add_helper;szFirewallHelper.add_helpercCs"||jkrttj||j|=dS)N)rrrr)rrrrr remove_helper>s  zFirewallHelper.remove_helperN) __name__ __module__ __qualname__r r rrrrrrrrrrrr rsN)__doc____all__ZfirewallrZfirewall.errorsrobjectrrrrr s  PKpge[K%__pycache__/fw_service.cpython-36.pycnu[3 gg@s2dgZddlmZddlmZGdddeZdS)FirewallService)errors) FirewallErrorc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)rcCs||_i|_dS)N)Z_fw _services)selffwr /usr/lib/python3.6/fw_service.py__init__szFirewallService.__init__cCsd|j|jfS)Nz%s(%r)) __class__r)rrrr __repr__ szFirewallService.__repr__cCs|jjdS)N)rclear)rrrr cleanup#szFirewallService.cleanupcCst|jjS)N)sortedrkeys)rrrr get_services(szFirewallService.get_servicescCs||jkrttj|dS)N)rrrZINVALID_SERVICE)rservicerrr check_service+s zFirewallService.check_servicecCs|j||j|S)N)rr)rrrrr get_service/s zFirewallService.get_servicecCs||j|j<dS)N)rname)robjrrr add_service3szFirewallService.add_servicecCs|j||j|=dS)N)rr)rrrrr remove_service6s zFirewallService.remove_serviceN) __name__ __module__ __qualname__r r rrrrrrrrrr rsN)__all__ZfirewallrZfirewall.errorsrobjectrrrrr s  PKpge[QQ%__pycache__/rich.cpython-36.opt-1.pycnu[3 g8@sdddddddddd d d d d ddddgZddlmZddlmZddlmZddlmZddlm Z Gddde Z Gddde Z Gddde Z Gddde ZGdddeZGddde ZGddde ZGddde ZGd dde ZGd!d d e ZGd"d d e ZGd#d d e ZGd$d d e ZGd%d d e ZGd&ddeZGd'dde Zd(d)d/d1d+ZGd,dde ZGd-dde Zd.S)2 Rich_SourceRich_Destination Rich_Service Rich_Port Rich_ProtocolRich_MasqueradeRich_IcmpBlock Rich_IcmpTypeRich_SourcePortRich_ForwardPortRich_Log Rich_Audit Rich_Accept Rich_Reject Rich_Drop Rich_Mark Rich_Limit Rich_Rule) functions)check_ipset_name) REJECT_TYPES)errors) FirewallErrorc@seZdZdddZddZdS)rFcCs||_|jdkrd|_||_|jdks0|jdkr8d|_n|jdk rN|jj|_||_|jdkrdd|_||_|jdkr|jdkr|jdkrttjddS)Nzno address, mac and ipset)addrmacupperipsetinvertrr INVALID_RULE)selfrrrrr!/usr/lib/python3.6/rich.py__init__$s    zRich_Source.__init__cCsjd|jr dnd}|jdk r*|d|jS|jdk rB|d|jS|jdk rZ|d|jSttjddS)Nz source%s z NOTrz address="%s"zmac="%s"z ipset="%s"zno address, mac and ipset)rrrrrrr)r retr!r!r"__str__5s   zRich_Source.__str__N)F)__name__ __module__ __qualname__r#r%r!r!r!r"r#s c@seZdZdddZddZdS)rFcCsV||_|jdkrd|_||_|jdkr,d|_||_|jdkrR|jdkrRttjddS)Nrzno address and ipset)rrrrrr)r rrrr!r!r"r#Bs  zRich_Destination.__init__cCsRd|jr dnd}|jdk r*|d|jS|jdk rB|d|jSttjddS)Nzdestination%s z NOTrz address="%s"z ipset="%s"zno address and ipset)rrrrrr)r r$r!r!r"r%Ns  zRich_Destination.__str__N)F)r&r'r(r#r%r!r!r!r"rAs c@seZdZddZddZdS)rcCs ||_dS)N)name)r r)r!r!r"r#YszRich_Service.__init__cCs d|jS)Nzservice name="%s")r))r r!r!r"r%\szRich_Service.__str__N)r&r'r(r#r%r!r!r!r"rXsc@seZdZddZddZdS)rcCs||_||_dS)N)portprotocol)r r*r+r!r!r"r#`szRich_Port.__init__cCsd|j|jfS)Nzport port="%s" protocol="%s")r*r+)r r!r!r"r%dszRich_Port.__str__N)r&r'r(r#r%r!r!r!r"r_sc@seZdZddZdS)r cCsd|j|jfS)Nz#source-port port="%s" protocol="%s")r*r+)r r!r!r"r%hszRich_SourcePort.__str__N)r&r'r(r%r!r!r!r"r gsc@seZdZddZddZdS)rcCs ||_dS)N)value)r r,r!r!r"r#mszRich_Protocol.__init__cCs d|jS)Nzprotocol value="%s")r,)r r!r!r"r%pszRich_Protocol.__str__N)r&r'r(r#r%r!r!r!r"rlsc@seZdZddZddZdS)rcCsdS)Nr!)r r!r!r"r#tszRich_Masquerade.__init__cCsdS)N masquerader!)r r!r!r"r%wszRich_Masquerade.__str__N)r&r'r(r#r%r!r!r!r"rssc@seZdZddZddZdS)rcCs ||_dS)N)r))r r)r!r!r"r#{szRich_IcmpBlock.__init__cCs d|jS)Nzicmp-block name="%s")r))r r!r!r"r%~szRich_IcmpBlock.__str__N)r&r'r(r#r%r!r!r!r"rzsc@seZdZddZddZdS)rcCs ||_dS)N)r))r r)r!r!r"r#szRich_IcmpType.__init__cCs d|jS)Nzicmp-type name="%s")r))r r!r!r"r%szRich_IcmpType.__str__N)r&r'r(r#r%r!r!r!r"rsc@seZdZddZddZdS)r cCs<||_||_||_||_|jdkr(d|_|jdkr8d|_dS)Nr)r*r+to_port to_address)r r*r+r.r/r!r!r"r#s  zRich_ForwardPort.__init__cCs<d|j|j|jdkrd|jnd|jdkr4d|jndfS)Nz(forward-port port="%s" protocol="%s"%s%srz to-port="%s"z to-addr="%s")r*r+r.r/)r r!r!r"r%szRich_ForwardPort.__str__N)r&r'r(r#r%r!r!r!r"r s c@seZdZdddZddZdS)r NcCs||_||_||_dS)N)prefixlevellimit)r r0r1r2r!r!r"r#szRich_Log.__init__cCs>d|jrd|jnd|jr$d|jnd|jr6d|jndfS)Nz log%s%s%sz prefix="%s"rz level="%s"z %s)r0r1r2)r r!r!r"r%szRich_Log.__str__)NNN)r&r'r(r#r%r!r!r!r"r s c@seZdZdddZddZdS)r NcCs ||_dS)N)r2)r r2r!r!r"r#szRich_Audit.__init__cCsd|jrd|jndS)Nzaudit%sz %sr)r2)r r!r!r"r%szRich_Audit.__str__)N)r&r'r(r#r%r!r!r!r"r s c@seZdZdddZddZdS)r NcCs ||_dS)N)r2)r r2r!r!r"r#szRich_Accept.__init__cCsd|jrd|jndS)Nzaccept%sz %sr)r2)r r!r!r"r%szRich_Accept.__str__)N)r&r'r(r#r%r!r!r!r"r s c@s&eZdZdddZddZddZdS) rNcCs||_||_dS)N)typer2)r Z_typer2r!r!r"r#szRich_Reject.__init__cCs,d|jrd|jnd|jr$d|jndfS)Nz reject%s%sz type="%s"rz %s)r3r2)r r!r!r"r%szRich_Reject.__str__cCsT|jrP|sttjd|dkrP|jt|krPdjt|}ttjd|j|fdS)Nz9When using reject type you must specify also rule family.ipv4ipv6z, z%Wrong reject type %s. Use one of: %s.)r4r5)r3rrrrjoin)r familyZ valid_typesr!r!r"checks zRich_Reject.check)NN)r&r'r(r#r%r8r!r!r!r"rs c@seZdZddZdS)rcCsd|jrd|jndS)Nzdrop%sz %sr)r2)r r!r!r"r%szRich_Drop.__str__N)r&r'r(r%r!r!r!r"rsc@s&eZdZdddZddZddZdS) rNcCs||_||_dS)N)setr2)r Z_setr2r!r!r"r#szRich_Mark.__init__cCsd|j|jrd|jndfS)Nz mark set=%s%sz %sr)r9r2)r r!r!r"r%szRich_Mark.__str__cCs|jdk r|j}n ttjdd|krv|jd}t|dkrHttj|tj|d shtj|d rttj|ntj|sttj|dS)Nz no value set/r)r9rrZ INVALID_MARKsplitlenrZ checkUINT32)r xsplitsr!r!r"r8s      zRich_Mark.check)N)r&r'r(r#r%r8r!r!r!r"rs r<<)smhdc@seZdZdddZddZeddZejddZed d Zejd d Ze d d Z ddZ e ddZ ddZ ddZdS)rNcCs||_||_dS)N)r,burst)r r,rGr!r!r"r#szRich_Limit.__init__cCs|j|jdS)N) value_parse burst_parse)r r!r!r"r8szRich_Limit.checkcCs|jS)N)_value)r r!r!r"r,szRich_Limit.valuec Csf|dkrd|_dSy|j|\}}Wntk r<|}YnX|d|}t|dd|krb||_dS)Nr:rJ)rJ _value_parsergetattr)r r,ratedurationvr!r!r"r,s cCs|jS)N)_burst)r r!r!r"rG szRich_Limit.burstc Cs\|dkrd|_dSy|j|}Wntk r8|}Yn Xt|}t|dd|krX||_dS)NrP)rP _burst_parserstrrL)r rGbr!r!r"rGs c Csd}d|kr|jd}| s(t|dkr4ttj||\}}y t|}Wnttj|YnX|dkrv|dd}|dks|dkrttj|d t||d krttjd|f|dkr|d krttjd|f||fS)Nr:r;secondminutehourdayr<rCrDrErFi'rz %s too fastz %s too slow)rTrUrVrW)rCrDrErF)r=r>rr INVALID_LIMITintDURATION_TO_MULT)r,r@rMrNr!r!r"rKs&     zRich_Limit._value_parsecCs |j|jS)N)rKrJ)r r!r!r"rH:szRich_Limit.value_parsec CsR|dkr dSy t|}Wnttj|YnX|dksB|dkrNttj||S)Nr<i)rYrrrX)rGrSr!r!r"rQ=s  zRich_Limit._burst_parsecCs |j|jS)N)rQrP)r r!r!r"rIKszRich_Limit.burst_parsecCs,d|jd}|jdk r(|d|j7}|S)Nz limit value=""z burst=)rJrP)r rCr!r!r"r%Ns zRich_Limit.__str__)N)r&r'r(r#r8propertyr,setterrG staticmethodrKrHrQrIr%r!r!r!r"rs     c@s>eZdZdZdZdddZddZd d Zd d Zd dZ dS)riiNrcCsV|dk rt||_nd|_||_d|_d|_d|_d|_d|_d|_|rR|j |dS)N) rRr7prioritysource destinationelementlogauditaction_import_from_string)r r7rule_strr_r!r!r"r#Xs zRich_Rule.__init__cCsg}x|tj|D]n}d|krp|jd}t|dksF|d sF|d rVttjd||j|d|ddq|jd|iqW|jddi|S) z Lexical analysis =r;rr<zinternal error in _lexer(): %s) attr_name attr_valuerbEOL)rZ splitArgsr=r>rrrappend)r rgtokensrattrr!r!r"_lexeris   zRich_Rule._lexerc Cs|sttjdtj|}d|_d|_d|_d|_d|_ d|_ d|_ d|_ |j |}|rv|djddkrvttjdi}g}d}x`||jddko|dgks||jd}||jd}||jd}|r|dHkrttjd|n|dIkr|dkr|jrttjd+n|dkr<|jr|d <nBt|jd |jd |jd |jd d?|_|j|j|d2}n| dkr,|dOkr|||<nN|dPkrd>|d <n:t|jd |jd |jd d?|_|j|j|d2}n| dkrd|dkrTt||_ |jn ttjd@nv| dkr|dkrt||_ |jn ttjdAn>| dkr|dQkr|||<n0t|jd|jd|_ |j|j|d2}n| dkr&|dkrt||_ |jn ttjdBn| dkr^|dkrNt||_ |jn ttjdCn|| dkrt|_ |j|j|d2}nN| d kr|dRkr|||<n@t|jd|jd|jd|jd|_ |j|j|d2}n| d!kr@|dSkr |||<n0t|jd|jd|_ |j|j|d2}n| d"kr|dTkr^|||<nN|d(krt|jd(n8t |jd|jd|jd(|_ |j|j|d2}n*| d#kr|d(kr|jd(n(t!|jd(|_ |j|j|d2}n| d$krH|d(kr|jd(n(t"|jd(|_ |j|j|d2}n| d%kr|d(krh|jd(n(t#|jd(|_ |j|j|d2}nF| d&kr|dkr|||<nF|d(kr|jd(n0t$|jd|jd(|_ |j|j|d2}n| d'kr`|dkr|||<nF|d(kr.|jd(n0t%|jd|jd(|_ |j|j|d2}nz| d(kr|dUkr||dD|<nVdE|krttjdFt&|dE|jdG|d(<|jdEd|jdGd|j|d2}|d2}qW|j'dS)VNz empty rulerrbrkrulerirjr_r7addressrrrr,r*r+to-portto-addrr)r0r1r3r9rGzbad attribute '%s'r`raservice icmp-block icmp-typer- forward-port source-portrcrdacceptdroprejectmarkr2notNOTzmore than one 'source' elementz#more than one 'destination' elementzFmore than one element. There cannot be both '%s' and '%s' in one rule.zmore than one 'log' elementzmore than one 'audit' elementzOmore than one 'action' element. There cannot be both '%s' and '%s' in one rule.zunknown element %sr<rz0'family' outside of rule. Use 'rule family=...'.z4'priority' outside of rule. Use 'rule priority=...'.z:'%s' outside of any element. Use 'rule %s= ...'.z,'%s' outside of rule. Use 'rule ... %s ...'.r4r5zH'family' attribute cannot have '%s' value. Use 'ipv4' or 'ipv6' instead.z(invalid 'priority' attribute value '%s'.zdwrong 'protocol' usage. Use either 'rule protocol value=...' or 'rule [forward-]port protocol=...'.zDattribute '%s' outside of any element. Use 'rule %s= ...'.TFzinvalid 'protocol' elementzinvalid 'service' elementzinvalid 'icmp-block' elementzinvalid 'icmp-type' elementzlimit.z limit.valuezinvalid 'limit' elementz limit.burst)r_r7rrrrrr,r*r+rsrtr)r0r1r3r9rG)rqr`rar+rur*rvrwr-rxryrcrdrzr{r|r}r2r~rrk)r+rur*rvrwr-rxry)rzr{r|r})r4r5)rrrrr)r~r)rrrr)r~r)r*r+)r*r+rsrt)r*r+)r0r1)r,rG)(rrrrZstripNonPrintableCharactersr_r7r`rarbrcrdrerpgetr>rlrY ValueErrorINVALID_PRIORITYrpopclearrrrrrrrr r r r r rrrrr8) r rgrmZattrsZ in_elementsindexrbrirjZ in_elementZerr_msgr!r!r"rfzs    ""               *      "                          (                                            zRich_Rule._import_from_stringc Cs`|jdk r"|jd kr"ttj|j|jdkrn|jdk rB|jjdk sL|jdk rVttjt|j t krnttj|j |j ks|j |j krttjd|j |j f|j dko|jdks|jdk o|j dkr |jdkrttjd|jdko|jdko|j dkr ttjdt|j tt tgkrP|jdkrP|jdkrP|jdkrPttjd|jdk rj|jjdk r|jdkrttj|jjdk rttjd|jjdk rttjd tj|j|jjsjttjt|jjn|jjdk r,|jjdk rttjd tj|jjsjttjt|jjn>|jjdk r^t|jjsjttjt|jjn ttjd |jdk r|jjdk r|jdkrttj|jjdk rttjd tj|j|jjsttjt|jjn>|jjdk rt|jjsttjt|jjn ttjd t|j t krd|j j!dksLt"|j j!d kr`ttj#t|j j!nt|j t$krtj%|j j&sttj'|j j&|j j(d!kr`ttj)|j j(nt|j t*krtj+|j j,s`ttj)|j j,nvt|j tkr<|jdk rttjd|jdk r`|jjdk r`ttjdn$t|j tkr|j j!dkslt"|j j!d krttj-t|j j!|jr`ttjdnt|j t.kr|j j!dkst"|j j!d kr`ttj-t|j j!nt|j t krtj%|j j&sttj'|j j&|j j(d"kr.ttj)|j j(|j j/dkrZ|j j0dkrZttj'|j j/|j j/dkrtj%|j j/ rttj'|j j/|j j0dkrtj1|j|j j0 rttj|j j0|jdkrttj|jdk r`ttjdnrt|j t2kr>tj%|j j&sttj'|j j&|j j(d#kr`ttj)|j j(n"|j dk r`ttjdt|j |jdk r|jj3r|jj3d$krttj4|jj3|jj5dk r|jj5j6|jdk rt|jt7t8t9gkrttj:t|j|jj5dk r|jj5j6|jdk r\t|jt8kr(|jj6|jnt|jt;krB|jj6|jj5dk r\|jj5j6dS)%Nr4r5z/'priority' attribute must be between %d and %d.rzno element, no actionz%no element, no source, no destinationzno action, no log, no auditzaddress and maczaddress and ipsetz mac and ipsetzinvalid sourcezinvalid destinationr<tcpudpsctpdccpzmasquerade and actionzmasquerade and mac sourcezicmp-block and actionrzforward-port and actionzUnknown element %semergalertcriterrorwarningnoticeinfodebug)r4r5)rrrr)rrrr)rrrr)rrrrrrrr)ZINVALID_SERVICErZ check_portr*Z INVALID_PORTr+ZINVALID_PROTOCOLrZ checkProtocolr,ZINVALID_ICMPTYPErr.r/Zcheck_single_addressr r1ZINVALID_LOG_LEVELr2r8r rrZINVALID_AUDIT_TYPEr)r r!r!r"r8hs                                          zRich_Rule.checkcCsd}|jr|d|j7}|jr,|d|j7}|jr@|d|j7}|jrT|d|j7}|jrh|d|j7}|jr||d|j7}|jr|d|j7}|jr|d|j7}tj rtj |S|S)Nrqz priority="%d"z family="%s"z %s) r_r7r`rarbrcrdrerZPY2Zu2b)r r$r!r!r"r%s$zRich_Rule.__str__i)NNr) r&r'r(rrr#rprfr8r%r!r!r!r"rTs o-NiiiQ)__all__ZfirewallrZfirewall.core.ipsetrZfirewall.core.baserrZfirewall.errorsrobjectrrrrr rrrrr r r r rrrrZrrr!r!r!r"s@      dPKpge[x  &__pycache__/fw_policies.cpython-36.pycnu[3 g @sVdgZddlmZddlmZddlmZddlmZddlm Z Gddde Z dS) FirewallPolicies)config)log)LockdownWhitelist)errors) FirewallErrorc@sDeZdZddZddZddZddZd d Zd d Zd dZ dS)rcCsd|_ttj|_dS)NF) _lockdownrrZLOCKDOWN_WHITELISTlockdown_whitelist)selfr !/usr/lib/python3.6/fw_policies.py__init__szFirewallPolicies.__init__cCsd|j|j|jfS)Nz %s(%r, %r)) __class__rr )r r r r __repr__#s zFirewallPolicies.__repr__cCsd|_|jjdS)NF)rr cleanup)r r r r r'szFirewallPolicies.cleanupcCs|dkr2tjd||jj|rtjddSn|dkrdtjd||jj|rtjddSnb|dkrtjd ||jj|rtjd dSn0|d krtjd ||jj|rtjd dSdS)Ncontextz#Doing access check for context "%s"zcontext matches.TZuidzDoing access check for uid %dz uid matches.userz Doing access check for user "%s"z user matches.Zcommandz#Doing access check for command "%s"zcommand matches.F)rZdebug2r Z match_contextZdebug3Z match_uidZ match_userZ match_command)r keyvaluer r r access_check-s*        zFirewallPolicies.access_checkcCs|jrttjdd|_dS)Nzenable_lockdown()T)rrrZALREADY_ENABLED)r r r r enable_lockdownDs z FirewallPolicies.enable_lockdowncCs|jsttjdd|_dS)Nzdisable_lockdown()F)rrrZ NOT_ENABLED)r r r r disable_lockdownIs z!FirewallPolicies.disable_lockdowncCs|jS)N)r)r r r r query_lockdownNszFirewallPolicies.query_lockdownN) __name__ __module__ __qualname__r rrrrrrr r r r rsN) __all__ZfirewallrZfirewall.core.loggerrZ#firewall.core.io.lockdown_whitelistrrZfirewall.errorsrobjectrr r r r s      PKpge[k-N)__pycache__/ebtables.cpython-36.opt-1.pycnu[3 g$@s&dgZddlZddlmZddlmZddlmZm Z m Z ddl m Z ddl mZddlmZmZddlZd gd d d gd d dgdZiZiZiZxejD]tZgee<eee<x\eeD]PZeejdeeejdeefeejdeeejdeqWqWGdddeZdS)ebtablesN)runProg)log)tempFilereadfile splitArgs)COMMANDS) ipXtables) FirewallError INVALID_IPVZBROUTINGZ PREROUTINGZ POSTROUTINGZOUTPUTZINPUTZFORWARD)ZbrouteZnatfilterz -N %s_directz-I %s 1 -j %s_directz-I %s_direct 1 -j RETURNz %s_directc@seZdZdZdZdZddZddZddZd d Z d d Z d dZ ddZ ddZ ddZddZddZddZddZddZd/d d!Zd"d#Zd$d%Zd&d'Zd(d)Zd0d+d,Zd-d.ZdS)1rZebFcCsBt|j|_td|j|_|j|_|j|_|jg|_ dS)Nz %s-restore) ripv_command_restore_command_detect_restore_noflush_optionZrestore_noflush_option_detect_concurrent_optionconcurrent_option fill_existsavailable_tables)selfr/usr/lib/python3.6/ebtables.py__init__9s    zebtables.__init__cCs$tjj|j|_tjj|j|_dS)N)ospathexistsrZcommand_existsrZrestore_command_exists)rrrrrAszebtables.fill_existscCs(d}t|jddg}|ddkr$d}|S)Nz --concurrentz-Lr)rr)rrretrrrrEs  z"ebtables._detect_concurrent_optionc Cs.g}y|j|dWntk r(dSXdS)NoffFT) set_rules ValueError)rrulesrrrrOs z'ebtables._detect_restore_noflush_optioncCsg}|jr |j|kr |j|j|dd|D7}tjd|j|jdj|t|j|\}}|dkr~td|jdj||f|S)NcSsg|] }d|qS)z%sr).0itemrrr ^sz"ebtables.__run..z %s: %s %s rz'%s %s' failed: %s) rappendrdebug2 __class__rjoinrr )rargsZ_argsstatusrrrrZ__runYs zebtables.__runcCs(x"dD]}||krttd|qWdS)N %%REJECT%%%%ICMP%% %%LOGTYPE%%z'%s' invalid for ebtables)r,r-r.)r r )rrulestrrrr_rule_validatefs zebtables._rule_validatecCs|tko|t|kS)N)BUILT_IN_CHAINS)rr tablechainrrris_chain_builtinlszebtables.is_chain_builtincCsJg}|r4|jd|d|g|jd|d|dddgn|jd|d|g|S)Nz-tz-Nz-I1z-jZRETURNz-X)r&)raddr3r4r!rrrbuild_chain_rulesps zebtables.build_chain_rulescCs8d|g}|r |d|t|g7}n |d|g7}||7}|S)Nz-tz-Iz-D)r0)rr7r3r4indexr*r/rrr build_rule{s  zebtables.build_rulecCs tj|S)N)r Zcommon_reverse_rule)rr*rrr reverse_ruleszebtables.reverse_rulecCstj|dS)N)r Zcommon_check_passthrough)rr*rrrcheck_passthroughszebtables.check_passthroughcCs tj|S)N)r Zcommon_reverse_passthrough)rr*rrrreverse_passthroughszebtables.reverse_passthroughc Cs<t}d}i}x|D]}|dd}|j|xTdD]L}y|j|} Wntk rZYq4Xt|| dkr4|j| |j| }q4Wx^tt|D]N} xHtjD]>} | || kr|| j do|| j d rd|| || <qWqW|j |gj |qWxD|D]<}|j d|x&||D]}|j dj|d qWqW|jtj|j} tjd |j|jd |j| jfg} | j d t|j| |jd \} }tjdkrt|j}|dk rd} xH|D]@}tjd| |fddd|j d stjddd| d7} qWtj|j| dkr8td|jdj| |fdS)Nr -t--table"z"%s"z*%s r% z %s: %s %sz%s: %dz --noflush)stdinz%8d: %sr)nofmtnlr)rEz'%s %s' failed: %s)r>r?)rr1r9r lenpoprangestringZ whitespace startswithendswith setdefaultr&writer)closerstatnamerr'r(rst_sizerZgetDebugLogLevelrZdebug3unlink)rr! log_deniedZ temp_filer3Z table_rulesZ_ruler/opticrPr*r+rlineslinerrrrsZ                zebtables.set_rulescCs|j||j|S)N)r1_ebtables__run)rr/rTrrrset_rules zebtables.set_ruleNc Csg}|r|gntj}xp|D]h}||jkr6|j|qy*|jd|dg|jj||j|Wqtk rtjd|YqXqW|S)Nz-tz-Lz#ebtables table '%s' does not exist.)r2keysrr&rZr rZdebug1)rr3rZtablesrrrget_available_tabless    zebtables.get_available_tablescCsiS)Nr)rr3rrrget_zone_table_chainsszebtables.get_zone_table_chainscCsFg}xs.     PKpge[ CC)__pycache__/fw_ipset.cpython-36.opt-1.pycnu[3 g%@sfdZdgZddlmZddlmZmZmZm Z ddl m Z ddl m Z ddlmZGdddeZd S) z ipset backend FirewallIPSet)log)remove_default_create_optionsnormalize_ipset_entrycheck_entry_overlaps_existingcheck_for_overlapping_entries)IPSet)errors) FirewallErrorc@seZdZddZddZddZddZd d Zd d Zd dZ d4ddZ ddZ ddZ d5ddZ ddZddZddZd6dd Zd!d"Zd#d$Zd%d&Zd7d'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd1d2Zd3S)8rcCs||_i|_dS)N)_fw_ipsets)selffwr/usr/lib/python3.6/fw_ipset.py__init__#szFirewallIPSet.__init__cCsd|j|jfS)Nz%s(%r)) __class__r )r rrr__repr__'szFirewallIPSet.__repr__cCs|jjdS)N)r clear)r rrrcleanup,szFirewallIPSet.cleanupcCs||jkrttj|dS)N) get_ipsetsr r Z INVALID_IPSET)r namerrr check_ipset/s zFirewallIPSet.check_ipsetcCs ||jkS)N)r)r rrrr query_ipset3szFirewallIPSet.query_ipsetcCst|jjS)N)sortedr keys)r rrrr6szFirewallIPSet.get_ipsetscCst|jdkS)Nr)lenr )r rrr has_ipsets9szFirewallIPSet.has_ipsetsFcCs&|j||j|}|r"|j||S)N)rr check_applied_obj)r rappliedobjrrr get_ipset<s    zFirewallIPSet.get_ipsetcCs4g}|jjr|j|jj|jjr0|j|jj|S)N)r Znftables_enabledappendZnftables_backendZ ipset_enabledZ ipset_backend)r backendsrrrr#Cs zFirewallIPSet.backendscCs0|j|jjkr ttjd|j||j|j<dS)Nz'%s' is not supported by ipset.)typer Zipset_supported_typesr r Z INVALID_TYPEr r)r r rrr add_ipsetKs zFirewallIPSet.add_ipsetcCs|j|}|jrh| rhy x|jD]}|j|q"WWqttk rd}zttj|WYdd}~XqtXn tj d||j|=dS)Nz,Keeping ipset '%s' because of timeout option) r rr# set_destroy Exceptionr r COMMAND_FAILEDrdebug1)r rZkeepr backendmsgrrr remove_ipsetQs    zFirewallIPSet.remove_ipsetc<Cs$|j|}x|jD]}|jdkr|j}||krd|jksv|jddksv|j||dksvt|j||dkry|j|Wn.tk r}zt t j |WYdd}~XnX|j j ry|j|j|j|jWn0tk r}zt t j |WYdd}~Xn&Xd|_d|jkr,|jddkr,qy|j|jWn0tk rl}zt t j |WYdd}~XnXx|jD]J}y|j|j|Wn0tk r}zt t j |WYdd}~XnXqvWqy|j|j|j|j|jdWn0tk r}zt t j |WYdd}~XqXd|_qWdS)Nipsettimeout0rT)r r#rZset_get_active_terseoptionsr$rm_def_cr_optsr&r'r r r(r _individual_callsZ set_creater set_flushentriesset_add set_restore)r rr r*Zactiver+entryrrr apply_ipset]sL     &  zFirewallIPSet.apply_ipsetcCs>x8|jD],}|j|}d|_tjd||j|q WdS)NFzApplying ipset '%s')rr rrr)r9)r rr rrr apply_ipsetss  zFirewallIPSet.apply_ipsetscCsxz|jD]n}|jdkrq x\|jD]P}y|j||j|Wq$tk rr}z|jtjkrb|WYdd}~Xq$Xq$Wq WdS)NZnftables) r#rr check_appliedr&r coder NOT_APPLIED)r r*r-r+rrrflushs   zFirewallIPSet.flushTcCs|j||djS)N)r)r!r$)r rrrrrget_typeszFirewallIPSet.get_typecCst|j|ddjjdS)NT)r,)rr!r$split)r rrrr get_dimensionszFirewallIPSet.get_dimensioncCs|j|}|j|dS)N)r!r)r rr rrrr;s zFirewallIPSet.check_appliedcCs|jsttj|jdS)N)rr r r=r)r r rrrrszFirewallIPSet.check_applied_objcCs.|j||d}d|jkr*|jddkr*dSdS)N)rZfamilyZinet6Zipv6Zipv4)r!r1)r rrr rrr get_familys  zFirewallIPSet.get_familycCs|j|dd}t|}tj||j|j||jkrFttj d||ft ||jy$x|j D]}|j |j |q^WWn.tk r}zttj|WYdd}~Xn&Xd|jks|jddkr|jj|dS)NT)rz'%s' already is in '%s'r.r/)r!rr check_entryr1r$r5r r ZALREADY_ENABLEDrr#r6rr'r(r")r rr8r r*r+rrr add_entrys  zFirewallIPSet.add_entrycCs|j|dd}t|}||jkr4ttjd||fy$x|jD]}|j|j|q@WWn.t k r}zttj |WYdd}~Xn&Xd|j ks|j ddkr|jj |dS)NT)rz'%s' not in '%s'r.r/) r!rr5r r Z NOT_ENABLEDr#Z set_deleterr'r(r1remove)r rr8r r*r+rrr remove_entrys zFirewallIPSet.remove_entrycCsD|j|dd}t|}d|jkr:|jddkr:ttj|||jkS)NT)rr.r/)r!rr1r r ZIPSET_WITH_TIMEOUTr5)r rr8r rrr query_entrys  zFirewallIPSet.query_entrycCs|j|dd}|jS)NT)r)r!r5)r rr rrr get_entriesszFirewallIPSet.get_entriescCs@|j|dd}t|x|D]}tj||j|jqWd|jksN|jddkrT||_y"x|jD]}|j|j q`WWn.t k r}zt t j |WYdd}~XnXd|_yXxR|jD]F}|jjrx8|jD]}|j|j |qWq|j|j |j|j|jdqWWn0t k r4}zt t j |WYdd}~XnXd|_dS)NT)rr.r/)r!rrrDr1r$r5r#r4rr'r r r(rr r3r6r7)r rr5r r8r*r+rrr set_entriess.  zFirewallIPSet.set_entriesN)F)F)T)T)__name__ __module__ __qualname__rrrrrrrr!r#r%r,r9r:r>r?rBr;rrCrErGrHrIrJrrrrr"s0  1   N)__doc____all__Zfirewall.core.loggerrZfirewall.core.ipsetrr2rrrZfirewall.core.io.ipsetrZfirewallr Zfirewall.errorsr objectrrrrrs    PKpge[0%__pycache__/prog.cpython-36.opt-1.pycnu[3 g@sddlZdgZdddZdS)NrunProgc Cs|dkr g}|g|}d}|r@t|d}|jj}WdQRXddi}y tj|tjtjtjd|d}Wntk r|d SX|j|\}} |j dd }|j |fS) NrZLANGCT)stdinstderrstdoutZ close_fdsenvzutf-8replace)r r ) openreadencode subprocessPopenPIPEZSTDOUTOSErrorZ communicatedecode returncode) progargvrargsZ input_stringZhandlerZprocessoutputZ err_outputr/usr/lib/python3.6/prog.pyrs$    )NN)r__all__rrrrrsPKpge[5)__pycache__/fw_ifcfg.cpython-36.opt-1.pycnu[3 g @sTdZddgZddlZddlZddlmZddlmZddlm Z ddZ d dZ dS) z.Functions to search for and change ifcfg filessearch_ifcfg_of_interfaceifcfg_set_zone_of_interfaceN)config)log)ifcfgcCstjjtjsdSxtttjtjD]`}|jds4q$xd D]}|j|r:q:q:Wd |krXq$t d tj|f}|j |j d |kr$|Sq$Wd tj|f}tjj|rt |}|j |SdS)z6search ifcfg file for the interface in config.IFCFGDIRNzifcfg-.bak.orig.rpmnew.rpmorig.rpmsave-range.z%s/%sZDEVICEz %s/ifcfg-%s)rrr r r r ) ospathexistsrZIFCFGDIRsortedlistdir startswithendswithrreadget) interfacefilenameZignored ifcfg_filer/usr/lib/python3.6/fw_ifcfg.pyr!s*   cCsn|dkr d}t|}|dk rj|jd|krj|jddko>|dk rjtjd||jf|jd||jdS)zYSet zone (ZONE=) in the ifcfg file that uses the interface (DEVICE=)NZZONEzSetting ZONE=%s in '%s')rrrZdebug1rsetwrite)Zzonerrrrrr?s ) __doc____all__rZos.pathZfirewallrZfirewall.core.loggerrZfirewall.core.io.ifcfgrrrrrrrs   PKpge[_X|j |q>W|s|jj ||} | r| \} }| rtj||ri} xH|D]@}g| |<x2t||D]"} | |j |jj|j| qWqWxb| D]Z}y|jj|| |Wn<tk r}ztjt j tj |WYdd}~XnXq0Wxh|jD]^\} }y | |WnFtk r}z(tjt j tj d| ||fWYdd}~XnXqWttj||jdS)Nz%s.execute(%s)FTz#Calling fail func %s(%s) failed: %s)rr%r&r-prerr Exceptiondebug1 traceback format_excerrorrZhandle_modulesr'r(r)r rrZCOMMAND_FAILEDpost)r r+rr r4ZerrorMsgdoner,msgZ module_returnZstatusZ undo_rulesrrrr r rexecutefsV    " & zFirewallTransaction.executecCs|tjdt|xd|jD]Z\}}y ||Wqtk rr}z(tjtjtjd|||fWYdd}~XqXqWdS)Nz%s.pre()z"Calling pre func %s(%s) failed: %s) rr%r&rr0r1r2r3r4)r rrr7r r rr/s zFirewallTransaction.precCs|tjdt|xd|jD]Z\}}y ||Wqtk rr}z(tjtjtjd|||fWYdd}~XqXqWdS)Nz %s.post()z#Calling post func %s(%s) failed: %s) rr%r&r r0r1r2r3r4)r rrr7r r rr5s zFirewallTransaction.postN)__name__ __module__ __qualname__rrrrrrrrrr!r"r#r$r-r8r/r5r r r rr s"@ ) __doc____all__r2Zfirewall.core.loggerrZfirewallrZfirewall.errorsrobjectrr r r rs    PKpge[ CC#__pycache__/fw_ipset.cpython-36.pycnu[3 g%@sfdZdgZddlmZddlmZmZmZm Z ddl m Z ddl m Z ddlmZGdddeZd S) z ipset backend FirewallIPSet)log)remove_default_create_optionsnormalize_ipset_entrycheck_entry_overlaps_existingcheck_for_overlapping_entries)IPSet)errors) FirewallErrorc@seZdZddZddZddZddZd d Zd d Zd dZ d4ddZ ddZ ddZ d5ddZ ddZddZddZd6dd Zd!d"Zd#d$Zd%d&Zd7d'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd1d2Zd3S)8rcCs||_i|_dS)N)_fw_ipsets)selffwr/usr/lib/python3.6/fw_ipset.py__init__#szFirewallIPSet.__init__cCsd|j|jfS)Nz%s(%r)) __class__r )r rrr__repr__'szFirewallIPSet.__repr__cCs|jjdS)N)r clear)r rrrcleanup,szFirewallIPSet.cleanupcCs||jkrttj|dS)N) get_ipsetsr r Z INVALID_IPSET)r namerrr check_ipset/s zFirewallIPSet.check_ipsetcCs ||jkS)N)r)r rrrr query_ipset3szFirewallIPSet.query_ipsetcCst|jjS)N)sortedr keys)r rrrr6szFirewallIPSet.get_ipsetscCst|jdkS)Nr)lenr )r rrr has_ipsets9szFirewallIPSet.has_ipsetsFcCs&|j||j|}|r"|j||S)N)rr check_applied_obj)r rappliedobjrrr get_ipset<s    zFirewallIPSet.get_ipsetcCs4g}|jjr|j|jj|jjr0|j|jj|S)N)r Znftables_enabledappendZnftables_backendZ ipset_enabledZ ipset_backend)r backendsrrrr#Cs zFirewallIPSet.backendscCs0|j|jjkr ttjd|j||j|j<dS)Nz'%s' is not supported by ipset.)typer Zipset_supported_typesr r Z INVALID_TYPEr r)r r rrr add_ipsetKs zFirewallIPSet.add_ipsetcCs|j|}|jrh| rhy x|jD]}|j|q"WWqttk rd}zttj|WYdd}~XqtXn tj d||j|=dS)Nz,Keeping ipset '%s' because of timeout option) r rr# set_destroy Exceptionr r COMMAND_FAILEDrdebug1)r rZkeepr backendmsgrrr remove_ipsetQs    zFirewallIPSet.remove_ipsetc<Cs$|j|}x|jD]}|jdkr|j}||krd|jksv|jddksv|j||dksvt|j||dkry|j|Wn.tk r}zt t j |WYdd}~XnX|j j ry|j|j|j|jWn0tk r}zt t j |WYdd}~Xn&Xd|_d|jkr,|jddkr,qy|j|jWn0tk rl}zt t j |WYdd}~XnXx|jD]J}y|j|j|Wn0tk r}zt t j |WYdd}~XnXqvWqy|j|j|j|j|jdWn0tk r}zt t j |WYdd}~XqXd|_qWdS)Nipsettimeout0rT)r r#rZset_get_active_terseoptionsr$rm_def_cr_optsr&r'r r r(r _individual_callsZ set_creater set_flushentriesset_add set_restore)r rr r*Zactiver+entryrrr apply_ipset]sL     &  zFirewallIPSet.apply_ipsetcCs>x8|jD],}|j|}d|_tjd||j|q WdS)NFzApplying ipset '%s')rr rrr)r9)r rr rrr apply_ipsetss  zFirewallIPSet.apply_ipsetscCsxz|jD]n}|jdkrq x\|jD]P}y|j||j|Wq$tk rr}z|jtjkrb|WYdd}~Xq$Xq$Wq WdS)NZnftables) r#rr check_appliedr&r coder NOT_APPLIED)r r*r-r+rrrflushs   zFirewallIPSet.flushTcCs|j||djS)N)r)r!r$)r rrrrrget_typeszFirewallIPSet.get_typecCst|j|ddjjdS)NT)r,)rr!r$split)r rrrr get_dimensionszFirewallIPSet.get_dimensioncCs|j|}|j|dS)N)r!r)r rr rrrr;s zFirewallIPSet.check_appliedcCs|jsttj|jdS)N)rr r r=r)r r rrrrszFirewallIPSet.check_applied_objcCs.|j||d}d|jkr*|jddkr*dSdS)N)rZfamilyZinet6Zipv6Zipv4)r!r1)r rrr rrr get_familys  zFirewallIPSet.get_familycCs|j|dd}t|}tj||j|j||jkrFttj d||ft ||jy$x|j D]}|j |j |q^WWn.tk r}zttj|WYdd}~Xn&Xd|jks|jddkr|jj|dS)NT)rz'%s' already is in '%s'r.r/)r!rr check_entryr1r$r5r r ZALREADY_ENABLEDrr#r6rr'r(r")r rr8r r*r+rrr add_entrys  zFirewallIPSet.add_entrycCs|j|dd}t|}||jkr4ttjd||fy$x|jD]}|j|j|q@WWn.t k r}zttj |WYdd}~Xn&Xd|j ks|j ddkr|jj |dS)NT)rz'%s' not in '%s'r.r/) r!rr5r r Z NOT_ENABLEDr#Z set_deleterr'r(r1remove)r rr8r r*r+rrr remove_entrys zFirewallIPSet.remove_entrycCsD|j|dd}t|}d|jkr:|jddkr:ttj|||jkS)NT)rr.r/)r!rr1r r ZIPSET_WITH_TIMEOUTr5)r rr8r rrr query_entrys  zFirewallIPSet.query_entrycCs|j|dd}|jS)NT)r)r!r5)r rr rrr get_entriesszFirewallIPSet.get_entriescCs@|j|dd}t|x|D]}tj||j|jqWd|jksN|jddkrT||_y"x|jD]}|j|j q`WWn.t k r}zt t j |WYdd}~XnXd|_yXxR|jD]F}|jjrx8|jD]}|j|j |qWq|j|j |j|j|jdqWWn0t k r4}zt t j |WYdd}~XnXd|_dS)NT)rr.r/)r!rrrDr1r$r5r#r4rr'r r r(rr r3r6r7)r rr5r r8r*r+rrr set_entriess.  zFirewallIPSet.set_entriesN)F)F)T)T)__name__ __module__ __qualname__rrrrrrrr!r#r%r,r9r:r>r?rBr;rrCrErGrHrIrJrrrrr"s0  1   N)__doc____all__Zfirewall.core.loggerrZfirewall.core.ipsetrr2rrrZfirewall.core.io.ipsetrZfirewallr Zfirewall.errorsr objectrrrrrs    PKpge[5#__pycache__/fw_ifcfg.cpython-36.pycnu[3 g @sTdZddgZddlZddlZddlmZddlmZddlm Z ddZ d dZ dS) z.Functions to search for and change ifcfg filessearch_ifcfg_of_interfaceifcfg_set_zone_of_interfaceN)config)log)ifcfgcCstjjtjsdSxtttjtjD]`}|jds4q$xd D]}|j|r:q:q:Wd |krXq$t d tj|f}|j |j d |kr$|Sq$Wd tj|f}tjj|rt |}|j |SdS)z6search ifcfg file for the interface in config.IFCFGDIRNzifcfg-.bak.orig.rpmnew.rpmorig.rpmsave-range.z%s/%sZDEVICEz %s/ifcfg-%s)rrr r r r ) ospathexistsrZIFCFGDIRsortedlistdir startswithendswithrreadget) interfacefilenameZignored ifcfg_filer/usr/lib/python3.6/fw_ifcfg.pyr!s*   cCsn|dkr d}t|}|dk rj|jd|krj|jddko>|dk rjtjd||jf|jd||jdS)zYSet zone (ZONE=) in the ifcfg file that uses the interface (DEVICE=)NZZONEzSetting ZONE=%s in '%s')rrrZdebug1rsetwrite)Zzonerrrrrr?s ) __doc____all__rZos.pathZfirewallrZfirewall.core.loggerrZfirewall.core.io.ifcfgrrrrrrrs   PKpge[xMlMl__pycache__/fw.cpython-36.pycnu[3 g@sdgZddlZddlZddlZddlZddlZddlmZddlm Z ddl m Z ddl m Z ddl m Z ddl mZdd l mZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddlmZddlmZddl m!Z!ddl"m#Z#ddl$m%Z%m&Z&ddl'm(Z(ddl)m*Z*ddl+m,Z,ddl-m.Z.ddl/m0Z0ddl1m2Z2m3Z3ddl4m5Z5ddl6m7Z7ddl8m9Z9ddl:m;Z;ddlmZ>Gd!dde?Z@dS)"FirewallN)config) functions) ipXtables)ebtables)nftables)ipset)modules)FirewallIcmpType)FirewallService) FirewallZone)FirewallDirect)FirewallConfig)FirewallPolicies) FirewallIPSet)FirewallTransaction)FirewallHelper)FirewallPolicy)nm_get_bus_namenm_get_interfaces_in_zone)log)firewalld_conf)Direct)service_reader)icmptype_reader) zone_readerZone) ipset_reader) IPSET_TYPES) helper_reader) policy_reader)errors) FirewallErrorc@seZdZdeddZddZddZdd Zd d Zdfd d ZddZ dgddZ ddZ ddZ ddZ ddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zdhd)d*Zdid+d,Zd-d.Zdjd/d0Zdkd1d2Zdld3d4Zd5d6Zd7d8Zd9d:Zd;d<Zd=d>Z d?d@Z!dAdBZ"dCdDZ#dEdFZ$dGdHZ%dIdJZ&dKdLZ'dMdNZ(dmdOdPZ)dQdRZ*dSdTZ+dUdVZ,dWdXZ-dYdZZ.d[d\Z/d]d^Z0d_d`Z1dadbZ2dcddZ3d(S)nrFcCsttj|_||_|jr>d|_d|_d|_d|_t |_ d|_ nrt j ||_d|_g|_t j||_d|_g|_tj|_d|_tj|_d|_g|_ tj||_d|_ tj|_t||_t||_t||_ t!||_"t#||_t$|_%t&||_t'||_(t)||_*|j+dS)NFT),rrFIREWALLD_CONF_firewalld_conf_offlineip4tables_enabledip6tables_enabledebtables_enabled ipset_enabledripset_supported_typesnftables_enabledr ip4tablesip4tables_backendipv4_supported_icmp_types ip6tablesip6tables_backendipv6_supported_icmp_typesrebtables_backendr ipset_backendrnftables_backendr modules_backendr icmptyper servicer zoner directrrpoliciesrrhelperrpolicy_Firewall__init_vars)selfZoffliner?/usr/lib/python3.6/fw.py__init__CsB               zFirewall.__init__cCsDd|j|j|j|j|j|j|j|j|j|j |j |j |j |j |jfS)Nz:%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)) __class__r&r'r(_state_panic _default_zone_module_refcount_markscleanup_on_exitcleanup_modules_on_exitipv6_rpfilter_enabledr)_individual_calls _log_denied)r>r?r?r@__repr__ks   zFirewall.__repr__cCsjd|_d|_d|_i|_g|_tj|_tj|_ tj |_ tj |_ tj|_tj|_tj|_tj|_tj|_dS)NZINITF)rCrDrErFrGrZFALLBACK_CLEANUP_ON_EXITrHZ FALLBACK_CLEANUP_MODULES_ON_EXITrIZFALLBACK_IPV6_RPFILTERrJZFALLBACK_INDIVIDUAL_CALLSrKZFALLBACK_LOG_DENIEDrLZFALLBACK_FIREWALL_BACKEND_firewall_backendZFALLBACK_FLUSH_ALL_ON_RELOAD_flush_all_on_reloadZFALLBACK_RFC3964_IPV4 _rfc3964_ipv4ZFALLBACK_ALLOW_ZONE_DRIFTING_allow_zone_drifting)r>r?r?r@Z __init_varstszFirewall.__init_varscCs|jr$d|jjkr$tjdd|_|jrHd|jjkrHtjdd|_|jrld|jjkrltjdd|_|j r|j r|j rtj dt j ddS)Nfilterziptables is not usable.Fzip6tables is not usable.zebtables is not usable.zNo IPv4 and IPv6 firewall.) r&r-get_available_tablesrinfo1r'r0r(r2r+fatalsysexit)r>r?r?r@ _check_tabless     zFirewall._check_tablesc Cszy|jjWn*tk r8tjdd|_g|_YnX|jj|_|jj |jj s||jj rltjdntjdd|_ |j r|jjd|_n|j r|jj|_ng|_|jj |jj s|jj rtjdntjdd|_|j r|jjd|_n|jr|jj|_ng|_|jj |jj sN|jj r>tjd ntjd d|_|jrv|j rv|jj rvtjd dS) Nz4ipset not usable, disabling ipset usage in firewall.FzFiptables-restore is missing, using individual calls for IPv4 firewall.zCiptables-restore and iptables are missing, disabling IPv4 firewall.ipv4zGip6tables-restore is missing, using individual calls for IPv6 firewall.zEip6tables-restore and ip6tables are missing, disabling IPv6 firewall.ipv6zHebtables-restore is missing, using individual calls for bridge firewall.zEebtables-restore and ebtables are missing, disabling bridge firewall.zSebtables-restore is not supporting the --noflush option, will therefore not be used)r3Zset_list ValueErrorrwarningr)r*Zset_supported_typesr-Z fill_existsrestore_command_existsZcommand_existsr&r+r4Zsupported_icmp_typesr.r0r'r1r2r(rKrestore_noflush_optiondebug1)r>r?r?r@ _start_checksL               zFirewall._start_checkc>Cstj}tjdtjy|jjWn8tk rZ}ztj|tjdWYdd}~Xn"X|jj drt|jj d}|jj dr|jj d}|dk r|j dBkrd|_ tjd|j |jj d r|jj d }|dk r|j dCkrd |_ |dk r|j dDkrd|_ tjd |j |jj drv|jj d}|dk rv|j dEkrvtjdy|j jWntk rtYnX|jj dr|jj d}|dk r|j dFkrd|_|j dGkrd |_|jrtjdn tjd|jj dr"|jj d}|dk r"|j dHkr"tjdd |_|jj drt|jj d}|dksT|j dkr\d|_n|j |_tjd|j|jj dr|jj d|_tjd|j|jj dr|jj d}|j dIkrd|_nd |_tjd|j|jj dr&|jj d}|j dJkrd|_nd |_tjd|j|jj dr||jj d}|j dKkrVd|_nd |_|jsntjdtjd |j|jjtj|j|j|j|js|jtjd!y|j jjWnZtk r }z<|j jrtjd"|j jj |ntjd"|j jj |WYdd}~XnX|jj!tj|j |j"tj#d#|j"tj$d#|j"tj%d$|j"tj&d$t'|j(j)d%krtjd&|j"tj*d'|j"tj+d'|j"tj,d(|j"tj-d(t'|j.j/d%krtjd)|j"tj0d*|j"tj1d*t'|j2j3d%kr&tj4d+t5j6d,|j"tj7d-|j"tj8d-d}x.dLD]&}||j2j3krLtj4d1|d }qLW|rt5j6d,||j2j3krd2|j2j3krd2}nd3|j2j3krd3}nd.}tjd4|||}n tjd5|t9tj:} t;jj?| |jj@tj| |jA||_B|jrdS|jCtjDd%krtEjE} tF|} |s|jG| d8|r|s|jHr|jIjJr| jKd | jL|r|rtjd9|jMjN|jO| d8| jKd | jL|jHrX|jIjJrXtjd:|jIjPtjd;|jQ| d8tjd<|j2jR| d8|j2jSd|jB| d8tjd=|jTjU| d8| jKd | jL|j>jVrVtjd>|j>jW| y| jKd | jLWnXtk r>} z$t| jXd?| jYr&| jYnd@WYdd} ~ Xntk rTYnX~ tjDd,krtEjE} tjZdA| | dS)MNz"Loading firewalld config file '%s'z0Using fallback firewalld configuration settings. DefaultZoneZ CleanupOnExitnofalseFzCleanupOnExit is set to '%s'ZCleanupModulesOnExityestrueTz#CleanupModulesOnExit is set to '%s'ZLockdownzLockdown is enabledZ IPv6_rpfilterzIPv6 rpfilter is enabledzIPV6 rpfilter is disabledZIndividualCallszIndividualCalls is enabled LogDeniedZoffzLogDenied is set to '%s'ZFirewallBackendzFirewallBackend is set to '%s'ZFlushAllOnReloadzFlushAllOnReload is set to '%s'Z RFC3964_IPv4zRFC3964_IPv4 is set to '%s'ZAllowZoneDriftingzAllowZoneDrifting is enabled. This is considered an insecure configuration option. It will be removed in a future release. Please consider disabling it now.z AllowZoneDrifting is set to '%s'zLoading lockdown whitelistz*Failed to load lockdown whitelist '%s': %srr6rzNo icmptypes found.r;r7zNo services found.r8zNo zones found.rTr<blockdroptrustedzZone '%s' is not available.ZpublicZexternalz+Default zone '%s' is not valid. Using '%s'.zUsing default zone '%s'zLoading direct rules file '%s'z)Failed to load direct rules file '%s': %s)use_transactionzUnloading firewall moduleszApplying ipsetszApplying default rule setzApplying used zoneszApplying used policiesz2Applying direct chains rules and passthrough rulesz Direct: %srNz%Flushing and applying took %f seconds)rdre)rfrg)rdre)rfrg)rdre)rfrg)rfrg)rdre)rdre)rdre)rirjrk)[rZ FALLBACK_ZONErrar#r$read Exceptionr^getlowerrHrIr:Zenable_lockdownr"rJrKrLrOrPrQrRr%Zset_firewalld_confcopydeepcopy_select_firewall_backendrbZlockdown_whitelistZquery_lockdownerrorfilenameZ set_policies_loaderZFIREWALLD_IPSETSZETC_FIREWALLD_IPSETSZFIREWALLD_ICMPTYPESZETC_FIREWALLD_ICMPTYPESlenr6 get_icmptypesZFIREWALLD_HELPERSZETC_FIREWALLD_HELPERSZFIREWALLD_SERVICESZETC_FIREWALLD_SERVICESr7 get_servicesZFIREWALLD_ZONESZETC_FIREWALLD_ZONESr8 get_zonesrWrXrYZFIREWALLD_POLICIESZETC_FIREWALLD_POLICIESrZFIREWALLD_DIRECTospathexistsr9Zset_permanent_configZ set_direct check_zonerErZZgetDebugLogLeveltimerflushr)rZ has_ipsetsexecuteclearr5unload_firewall_modulesapply_default_tablesZ apply_ipsetsapply_default_rulesZ apply_zoneschange_default_zoner<Zapply_policiesZhas_configurationZ apply_directcodemsgZdebug2)r>reloadcomplete_reloadZ default_zonervaluertzr8objZtm1 transactioneZtm2r?r?r@_startst                                                           .zFirewall._startc CsHy |jWn&tk r2d|_|jdYnXd|_|jddS)NFAILEDACCEPTRUNNING)rrnrC set_policy)r>r?r?r@starts  zFirewall.startc Cshtjj|sdS|rZ|jtjrV|dkrVt}tjj||_|j |j||_d|_ nd}x|t tj |D]h}|j ds|jtjrl|dkrltjjd||frl|jd||f|ddqld||f}tjd||y|dkrt||}|j|jjkr8|jj|j}tjd ||j|j|j|jj|jn|jjtjrNd|_ y|jj|Wn<tk r} ztjd |jt| fWYdd} ~ XnX|jjtj|n|d krFt||}|j|jjkr|jj |j}tjd ||j|j|j|jj!|jn|jjtjr$d|_ |jj"||jj"tj|n.|dkrnt#|||d }|rdtjj|tjj|d df|_|j |jtj|} |j|j$j%kr|j$j&|j}|j$j'|j|j(rtjd||j|||j)|ntjd ||j|j|jn|jjtjr,d|_ d| _ |jj*| |r^tjd||j|||j)|n |j$j*|n|dkrDt+||}|j|j,j-kr|j,j.|j}tjd ||j|j|j|j,j/|jn|jjtjrd|_ y|j,j0|Wn<tk r,} ztj1d |jt| fWYdd} ~ XnX|jj0tj|n0|dkrt2||}|j|j3j4kr|j3j5|j}tjd ||j|j|j|j3j6|jn|jjtjrd|_ |j3j7||jj7tj|n|dkrht8||}|j|j9j:kr2|j9j;|j}tjd ||j|j|j|j9j<|jn|jjtjrHd|_ |j9j=||jj>tj|n tj?d|Wqltk r} ztj@d||| WYdd} ~ XqltAk rtj@d||tjBYqlXqlW|rd|j(rd|j|j$j%krX|j$j&|j}tjd||j|j|jy|j$j'|jWntAk rHYnX|jjC|j|j$j*|dS)Nr8Fz.xmlz%s/%sT)combinezLoading %s file '%s'r6z Overloads %s '%s' ('%s/%s')z%s: %s, ignoring for run-time.r7)Z no_check_namerz Combining %s '%s' ('%s/%s')rr;r<zUnknown reader type %szFailed to load %s file '%s': %szFailed to load %s file '%s':z0 Overloading and deactivating %s '%s' ('%s/%s'))Dr{r|isdir startswithrZ ETC_FIREWALLDrbasenamenameZ check_namedefaultsortedlistdirendswithrvrrarr6rxZ get_icmptyperuZremove_icmptypeZ add_icmptyper"rVstrrqrrrr7ryZ get_serviceZremove_serviceZ add_servicerr8rzZget_zoneZ remove_zonecombinedrZadd_zonerr get_ipsets get_ipsetZ remove_ipset add_ipsetr^rr;Z get_helpersZ get_helperZ remove_helperZ add_helperr r< get_policiesZ get_policyZ remove_policyZ add_policyZadd_policy_objectrWrtrnZ exceptionZ forget_zone) r>r|Z reader_typerZ combined_zonerurrZorig_objrtZ config_objrr?r?r@rvs       $             $       zFirewall._loadercCsp|jj|jj|jj|jj|jj|jj|jj|jj|j j|j j|j dS)N) r6cleanupr7r8rr;rr9r:r<r$r=)r>r?r?r@rs          zFirewall.cleanupcCsN|jsB|jr(|j|jj|jd|jrBtjd|jj |j dS)Nrz!Unloading firewall kernel modules) r%rHrrrrIrrar5rr)r>r?r?r@stops    z Firewall.stopc Csd}d}xt|D]\}}|r0|jj|\}}n$|j|dkrDd}n|jj|\}}|dkrn|d7}||7}q|r|jj|d|j|d7<q||jkr|j|d8<|j|dkr|j|=qW||fS)NrrNrT) enumerater5 load_modulerFZ unload_module setdefault) r>Z_modulesenableZ num_failedZ error_msgsimoduleZstatusrr?r?r@handle_moduless(  zFirewall.handle_modulescCs|dkrd|_dS)NrF)r+)r>backendr?r?r@rssz!Firewall._select_firewall_backendcCs4x|jD]}|j|kr |Sq Wttjd|dS)Nz'%s' backend does not exist) all_backendsrr"r!Z UNKNOWN_ERROR)r>rrr?r?r@get_backend_by_names  zFirewall.get_backend_by_namecCs\|jr |jS|dkr |jr |jS|dkr4|jr4|jS|dkrH|jrH|jStt j d|dS)Nr[r\ebz-'%s' is not a valid backend or is unavailable) r+r4r&r-r'r0r(r2r"r! INVALID_IPV)r>ipvr?r?r@get_backend_by_ipvszFirewall.get_backend_by_ipvcCsP|dkr|jr|jS|dkr(|jr(|jS|dkr<|jr<|jSttjd|dS)Nr[r\rz-'%s' is not a valid backend or is unavailable) r&r-r'r0r(r2r"r!r)r>rr?r?r@get_direct_backend_by_ipvsz"Firewall.get_direct_backend_by_ipvcCs<|dkr|jS|dkr|jS|dkr*|jS|dkr8|jSdS)Nr,r/rrF)r&r'r(r+)r>rr?r?r@is_backend_enabledszFirewall.is_backend_enabledcCs8|jr dS|dkr|jS|dkr&|jS|dkr4|jSdS)NTr[r\rF)r+r&r'r()r>rr?r?r@is_ipv_enabledszFirewall.is_ipv_enabledcCsRg}|jr|j|jn6|jr*|j|j|jr<|j|j|jrN|j|j|S)N) r+appendr4r&r-r'r0r(r2)r>backendsr?r?r@enabled_backends s   zFirewall.enabled_backendscCsPg}|jr|j|j|jr(|j|j|jr:|j|j|jrL|j|j|S)N) r&rr-r'r0r(r2r+r4)r>rr?r?r@rs    zFirewall.all_backendsNcCsN|dkrt|}n|}x |jD]}|j||jq W|dkrJ|jddS)NT)rr add_rulesZbuild_default_tablesr)r>rlrrr?r?r@r$s zFirewall.apply_default_tablescCs|dkrt|}n|}x(|jD]}|j|j}|j||q W|jdr~|jd}d|jkr~|jr~|j |j}|j|||jdr|j r|j }|j|||dkr|j ddS)Nr\rawT) rrZbuild_default_rulesrLrrrrUrJZbuild_rpfilter_rulesrQZbuild_rfc3964_ipv4_rulesr)r>rlrrrulesZ ipv6_backendr?r?r@r0s"        zFirewall.apply_default_rulescCs|jr|jj rdSdS)NTF)r+r9Zhas_runtime_configuration)r>r?r?r@may_skip_flush_direct_backendsHsz'Firewall.may_skip_flush_direct_backendscCs`|dkrt|}n|}x2|jD]&}||jkr2q |j}|j||q W|dkr\|jddS)NT)rrrbuild_flush_rulesrr)r>rlrrrr?r?r@flush_direct_backendsNs  zFirewall.flush_direct_backendscCsp|dkrt|}n|}tjd|js4|j|dx$|jD]}|j}|j||q>W|dkrl|jddS)NzFlushing rule set)rlT) rrrarrrrrr)r>rlrrrr?r?r@r]s   zFirewall.flushcCs`|dkrt|}n|}tjd|x&|jD]}|j|}|j||q,W|dkr\|jddS)NzSetting policy to '%s'T)rrrarZbuild_set_policy_rulesrr)r>r<rlrrrr?r?r@ros   zFirewall.set_policycCsB|sdS|j|}|s&ttjd||j|s4dS|j||jS)NrNz'%s' is not a valid backend)rr"r!rrset_rulerL)r> backend_namerulerr?r?r@rs   z Firewall.rulecCs"ttd|}|j|}|s,ttjd||j|s:dS|js\|j s\|dkoX|j j rxt |D]\}}y|j ||j Wqftk r}zjtjtjtj|xFt|d|D]2}y|j |j||j Wqtk rYqXqW|WYdd}~XqfXqfWn|j||j dS)Nz'%s' is not a valid backendr)listrSrr"r!rrrKr_r2r`rrrLrnrra traceback format_excrtreversedZ reverse_ruleZ set_rules)r>rrZ_rulesrrrrr?r?r@rs.     zFirewall.rulescCs|jrttjdS)N)rDr"r!Z PANIC_MODE)r>r?r?r@ check_panicszFirewall.check_paniccCs"|}||jjkrttj||S)N)r<rr"r!ZINVALID_POLICY)r>r<Z_policyr?r?r@ check_policys zFirewall.check_policycCs8|}| s|dkr|j}||jjkr4ttj||S)NrN)get_default_zoner8rzr"r!Z INVALID_ZONE)r>r8_zoner?r?r@r~s  zFirewall.check_zonecCstj|sttj|dS)N)rZcheckInterfacer"r!ZINVALID_INTERFACE)r> interfacer?r?r@check_interfaces zFirewall.check_interfacecCs|jj|dS)N)r7 check_service)r>r7r?r?r@rszFirewall.check_servicecCstj|sttj|dS)N)r check_portr"r!Z INVALID_PORT)r>Zportr?r?r@rs zFirewall.check_portcCs*|sttj|dkr&ttjd|dS)Ntcpudpsctpdccpz''%s' not in {'tcp'|'udp'|'sctp'|'dccp'})rrrr)r"r!ZMISSING_PROTOCOLZINVALID_PROTOCOL)r>Zprotocolr?r?r@ check_tcpudps  zFirewall.check_tcpudpcCstj|sttj|dS)N)rZcheckIPr"r! INVALID_ADDR)r>Zipr?r?r@check_ips zFirewall.check_ipcCsP|dkr tj|sLttj|n,|dkr@tj|sLttj|n ttjddS)Nr[r\z'%s' not in {'ipv4'|'ipv6'})rZ checkIPnMaskr"r!rZ checkIP6nMaskr)r>rsourcer?r?r@ check_addresss  zFirewall.check_addresscCs|jj|dS)N)r6check_icmptype)r>Zicmpr?r?r@rszFirewall.check_icmptypecCs>t|tstd|t|ft|dkr:ttjd|dS)Nz%s is %s, expected intrz#timeout '%d' is not positive number) isinstanceint TypeErrortyper"r! INVALID_VALUE)r>Ztimeoutr?r?r@ check_timeouts   zFirewall.check_timeoutc Cs`|j}|j}|sNi}x&|jjD]}|jj|d||<q W|jj}|j}g}x$|jj D]} |j |jj | q^W|s|j d|j |jd} y|jd|dWn&tk r} z | } WYdd} ~ XnX|r(xL|D]D} |jj| jsx0|jjD]"} | jdkrq| j| jqWqW|s|j}||kr||krRi||<xFt||jD]2\}}|drd||||||<|||=qdWxb|jjD]T}||krx.||D]"}|jj|||||dqW||=n tjd|qWt|d kr6x(t|jD]}tjd |||=qW~x|D]} |jj| jrxx| jD]R}y|jj| j|Wn6tk r}z|jt j!kr|WYdd}~XnXqZWn|jj"| |jj#| jq>W|jj$|t%}|r,x@|jjd gD],}x$t&|D]}|jj|||d q WqW||_|jsD|j d | rVd|_'| nd|_'dS)N interfacesZDROPT)rrr __default__senderzNew zone '%s'.rz(Lost zone '%s', zone interfaces dropped.rN)rrrr)(rDrPr8rz get_settingsr9Zget_runtime_configrrrrrrrrrrnZ query_ipsetrrZ set_destroyritemschange_zone_of_interfacerrVrwkeysZentriesZ add_entryr"rr!ALREADY_ENABLEDrZ apply_ipsetZ set_configrrrC)r>rrDZ flush_allZ_zone_interfacesr8Z_direct_config_old_dzZ _ipset_objs_nameZstart_exceptionrrrZ_new_dzifacesettingsZ interface_identryrZ nm_bus_namerr?r?r@rs                zFirewall.reloadcCs|jS)N)rC)r>r?r?r@ get_stateaszFirewall.get_statecCsZ|jrttjdy|jdWn.tk rN}zttj|WYdd}~XnXd|_dS)Nzpanic mode already enabledZPANICT)rDr"r!rrrnCOMMAND_FAILED)r>rr?r?r@enable_panic_modefszFirewall.enable_panic_modecCsZ|jsttjdy|jdWn.tk rN}zttj|WYdd}~XnXd|_dS)Nzpanic mode is not enabledrF)rDr"r!Z NOT_ENABLEDrrnr)r>rr?r?r@disable_panic_modeqszFirewall.disable_panic_modecCs|jS)N)rD)r>r?r?r@query_panic_mode|szFirewall.query_panic_modecCs|jS)N)rL)r>r?r?r@get_log_deniedszFirewall.get_log_deniedcCsb|tjkr&ttjd|djtjf||jkrR||_|jj d||jj n ttj |dS)Nz'%s', choose from '%s'z','rh) rZLOG_DENIED_VALUESr"r!rjoinrrLr$setwriteZ ALREADY_SET)r>rr?r?r@set_log_denieds   zFirewall.set_log_deniedcCs|jS)N)rE)r>r?r?r@rszFirewall.get_default_zonecCs|j|}||jkr|j}||_|jjd||jj|jj|||jj|}x@t|dj D]\}}|drd|jj d|qdWn t t j |dS)NrcrrrN)r~rEr$rrr8rrrrrr"r!ZZONE_ALREADY_SET)r>r8rrZ_old_dz_settingsrrr?r?r@set_default_zones    zFirewall.set_default_zonecCsH|j}x:|jD].\}}|s(t|tr2|||<q||kr||=qW|S)N)rqrrbool)r>Z permanentZruntimerkeyrr?r?r@'combine_runtime_with_permanent_settingss  z0Firewall.combine_runtime_with_permanent_settingscCsi}i}xt|jt|jBD]}||kr"t||trt||krN||ng}tt|||||<t|t||A|@||<q"t||tst||tr|| r||rd||<q||r|| rd||<q"ttjdj t |||q"W||fS)NTFz Unhandled setting type {} key {}) rrrrrrr"r!ZINVALID_SETTINGformatr)r>Z old_settingsZ new_settingsZ add_settingsZremove_settingsroldr?r?r@get_added_and_removed_settingss   z'Firewall.get_added_and_removed_settings)F)FF)F)N)N)N)N)N)F)4__name__ __module__ __qualname__rArMr=rZrbrrrvrrrrsrrrrrrrrrrrrrrrrrr~rrrrrrrrrrrrrrrrrrrr?r?r?r@rBsh ( ;                s  )A__all__Zos.pathr{rXrqrrZfirewallrrZ firewall.corerrrrr Zfirewall.core.fw_icmptyper Zfirewall.core.fw_servicer Zfirewall.core.fw_zoner Zfirewall.core.fw_directr Zfirewall.core.fw_configrZfirewall.core.fw_policiesrZfirewall.core.fw_ipsetrZfirewall.core.fw_transactionrZfirewall.core.fw_helperrZfirewall.core.fw_policyrZfirewall.core.fw_nmrrZfirewall.core.loggerrZfirewall.core.io.firewalld_confrZfirewall.core.io.directrZfirewall.core.io.servicerZfirewall.core.io.icmptyperZfirewall.core.io.zonerrZfirewall.core.io.ipsetrZfirewall.core.ipsetrZfirewall.core.io.helperrZfirewall.core.io.policyr r!Zfirewall.errorsr"objectrr?r?r?r@sH                            PKpge[#+oVq"q"&__pycache__/ipset.cpython-36.opt-1.pycnu[3 gq2 @sdZdddgZddlZddlZddlmZddlmZddl m Z dd l m Z dd l mZmZdd lmZd Zd ddddddddddg ZdddddZddddZGd ddeZd!dZd"dZd#d$Zd%d&Zd'd(ZdS))zThe ipset command wrapperipsetcheck_ipset_nameremove_default_create_optionsN)errors) FirewallError)runProg)log)tempFilereadfile)COMMANDS zhash:ipz hash:ip,portzhash:ip,port,ipzhash:ip,port,netz hash:ip,markzhash:netz hash:net,netz hash:net,portzhash:net,port,netzhash:net,ifacezhash:macz inet|inet6valuez value in secs)familyhashsizemaxelemtimeoutZinetZ1024Z65536)rrrc@seZdZdZddZddZddZdd Zd d Zd'd dZ ddZ ddZ ddZ d(ddZ d)ddZddZd*ddZd+ddZdd Zd!d"Zd#d$Zd%d&Zd S),rzipset command wrapper classcCstd|_d|_dS)Nr)r _commandname)selfr/usr/lib/python3.6/ipset.py__init__Ks zipset.__init__cCs^dd|D}tjd|j|jdj|t|j|\}}|dkrZtd|jdj||f|S)zCall ipset with argscSsg|] }d|qS)z%sr).0itemrrr Rszipset.__run..z %s: %s %s rz'%s %s' failed: %s)rdebug2 __class__rjoinr ValueError)rargsZ_argsstatusretrrrZ__runOsz ipset.__runcCs t|tkrttjd|dS)zCheck ipset namezipset name '%s' is not validN)lenIPSET_MAXNAMELENrrZ INVALID_NAME)rrrrr check_nameZs zipset.check_namecCsg}d}y|jdg}Wn0tk rH}ztjd|WYdd}~XnX|j}d}xT|D]L}|r|jjdd}|d|kr|dtkr|j|d|j dr\d }q\W|S) z?Return types that are supported by the ipset command and kernelz--helpzipset error: %sNFrzSupported set types:T) _ipset__runrrZdebug1 splitlinesstripsplit IPSET_TYPESappend startswith)rr"outputZexlinesZin_typeslinesplitsrrrset_supported_types`s    zipset.set_supported_typescCs(t|tks|tkr$ttjd|dS)zCheck ipset typez!ipset type name '%s' is not validN)r#r$r,rrZ INVALID_TYPE)r type_namerrr check_typeuszipset.check_typeNcCsd|j||j|d||g}t|trZx0|jD]$\}}|j||dkr2|j|q2W|j|S)z+Create an ipset with name, type and optionscreater&)r%r5 isinstancedictitemsr-r()rset_namer4optionsr keyvalrrr set_create{s     zipset.set_createcCs|j||jd|gS)NZdestroy)r%r()rr:rrr set_destroys zipset.set_destroycCsd||g}|j|S)Nadd)r()rr:entryr rrrset_adds z ipset.set_addcCsd||g}|j|S)Ndel)r()rr:rAr rrr set_deletes zipset.set_deletecCs,d||g}|r"|jddj||j|S)Ntestz%sr)r-rr()rr:rAr;r rrrrEs z ipset.testcCs2dg}|r|j||r"|j||j|jdS)Nlist )r-extendr(r+)rr:r;r rrrset_lists   zipset.set_listc Cs<|jdgd}i}d}}i}x|D] }t|dkr:q&dd|jddD}t|dkr`q&q&|d d krv|d}q&|d d kr|d}q&|d d kr&|dj}d } x^| t|kr|| } | dkrt|| kr| d7} || || <ntjd|iS| d7} qW|r$|r$|t|f||<d}}|jq&W|S)z" Get active ipsets (only headers) z-terse)r;NcSsg|] }|jqSr)r*)rxrrrrsz.ipset.set_get_active_terse..:r'rNameZTypeZHeaderrrrrnetmaskz&Malformed ipset list -terse output: %s)rrrrrN)rIr#r+rerrorrclear) rr0r"_nameZ_type_optionsr1Zpairr2ioptrrrset_get_active_tersesD            zipset.set_get_active_tersecCsdg}|r|j||j|S)Nsave)r-r()rr:r rrrrVs z ipset.savecCs|j||j|t}d|kr*d|}d||dg}|rlx0|jD]$\}} |j|| dkrD|j| qDW|jddj||jd|xN|D]F} d| krd| } |r|jd|| dj|fq|jd || fqW|jtj |j } t j d |j |jd |j | jfd g}t|j||j d \} } t jdkryt|j Wntk r`YnVXd}xNt|j D]@}t jd||fddd|jdst jddd|d7}qrWtj|j | dkrtd|jdj|| f| S)Nrz'%s'r6z-existr&z%s z flush %s z add %s %s %s z add %s %s z%s: %s restore %sz%s: %dZrestore)stdinr'rJz%8d: %sr)nofmtnlrG)rXz'%s %s' failed: %s)r%r5r r9r-writercloseosstatrrrrrst_sizerZgetDebugLogLevelr ExceptionZdebug3endswithunlinkr)rr:r4entriesZcreate_optionsZ entry_optionsZ temp_filer r<r=rAr]r!r"rSr1rrr set_restoresV         zipset.set_restorecCsdg}|r|j||j|S)Nflush)r-r()rr:r rrr set_flushs zipset.set_flushcCs|jd||gS)Nrename)r()rZ old_set_nameZ new_set_namerrrrf sz ipset.renamecCs|jd||gS)Nswap)r()rZ set_name_1Z set_name_2rrrrgsz ipset.swapcCs |jdgS)Nversion)r()rrrrrhsz ipset.version)N)N)NN)N)NN)__name__ __module__ __qualname____doc__rr(r%r3r5r>r?rBrDrErIrUrVrcrerfrgrhrrrrrHs&    '  7cCst|tkrdSdS)z"Return true if ipset name is validFT)r#r$)rrrrrs cCs8|j}x*tD]"}||krt|||kr||=qW|S)z( Return only non default create options )copyIPSET_DEFAULT_CREATE_OPTIONS)r;rRrTrrrrs   c Cshg}xX|jdD]J}y&|jd|jttj|ddWqtk rX|j|YqXqWdj|S)z! Normalize IP addresses in entry ,/F)strict)r+indexr-str ipaddress ip_networkrr)rAZ_entryZ_partrrrnormalize_ipset_entry&s rvcCsxt|jddkrdSytj|dd}Wntk r<dSXx4|D],}|jtj|ddrDttjdj ||qDWdS)z: Check if entry overlaps any entry in the list of entries rorJNF)rqz,Entry '{}' overlaps with existing entry '{}') r#r+rtruroverlapsrr INVALID_ENTRYformat)rArbZ entry_networkZitrrrrcheck_entry_overlaps_existing2s rzcCs~ydd|D}Wntk r&dSXt|dkr8dS|j|jd}x.|D]&}|j|rrttjdj|||}qPWdS)z> Check if any entry overlaps any entry in the list of entries cSsg|]}tj|ddqS)F)rq)rtru)rrKrrrrEsz1check_for_overlapping_entries..NrzEntry '{}' overlaps entry '{}') rr#sortpoprwrrrxry)rbZ prev_networkZcurrent_networkrrrcheck_for_overlapping_entriesBs 2   r})rl__all__Zos.pathr\rtZfirewallrZfirewall.errorsrZfirewall.core.progrZfirewall.core.loggerrZfirewall.functionsr r Zfirewall.configr r$r,ZIPSET_CREATE_OPTIONSrnobjectrrrrvrzr}rrrrsF      P  PKpge[zz__pycache__/base.cpython-36.pycnu[3 g6@sdZdZdZd0ZdddedgZddddgZd d d d d ddZddddddddddddddddgd d!d"d#d$d%d&ddg d'Zd(d)d*d+d,d-d.gZd/S)1zBase firewall settingsz{chain}_{zone}ZCONTINUEZACCEPTz %%REJECT%%ZDROPdefaultZREJECTZPREZPOSTINZFWDIZFWDOZOUT)Z PREROUTINGZ POSTROUTINGZINPUTZ FORWARD_INZ FORWARD_OUTZOUTPUTzicmp-host-prohibitedz host-prohibzicmp-net-unreachablez net-unreachzicmp-host-unreachablez host-unreachzicmp-port-unreachablez port-unreachzicmp-proto-unreachablez proto-unreachzicmp-net-prohibitedz net-prohibz tcp-resetztcp-rstzicmp-admin-prohibitedz admin-prohibzicmp6-adm-prohibitedzadm-prohibitedzicmp6-no-routezno-routezicmp6-addr-unreachablez addr-unreachzicmp6-port-unreachable)Zipv4Zipv6zhash:ipz hash:ip,portz hash:ip,markzhash:netz hash:net,portzhash:net,ifacezhash:macN) __doc__ZDEFAULT_ZONE_TARGETZDEFAULT_POLICY_TARGETZDEFAULT_POLICY_PRIORITYZ ZONE_TARGETSZPOLICY_TARGETSZ SHORTCUTSZ REJECT_TYPESZSOURCE_IPSET_TYPESrr/usr/lib/python3.6/base.pys. PKpge[#+oVq"q" __pycache__/ipset.cpython-36.pycnu[3 gq2 @sdZdddgZddlZddlZddlmZddlmZddl m Z dd l m Z dd l mZmZdd lmZd Zd ddddddddddg ZdddddZddddZGd ddeZd!dZd"dZd#d$Zd%d&Zd'd(ZdS))zThe ipset command wrapperipsetcheck_ipset_nameremove_default_create_optionsN)errors) FirewallError)runProg)log)tempFilereadfile)COMMANDS zhash:ipz hash:ip,portzhash:ip,port,ipzhash:ip,port,netz hash:ip,markzhash:netz hash:net,netz hash:net,portzhash:net,port,netzhash:net,ifacezhash:macz inet|inet6valuez value in secs)familyhashsizemaxelemtimeoutZinetZ1024Z65536)rrrc@seZdZdZddZddZddZdd Zd d Zd'd dZ ddZ ddZ ddZ d(ddZ d)ddZddZd*ddZd+ddZdd Zd!d"Zd#d$Zd%d&Zd S),rzipset command wrapper classcCstd|_d|_dS)Nr)r _commandname)selfr/usr/lib/python3.6/ipset.py__init__Ks zipset.__init__cCs^dd|D}tjd|j|jdj|t|j|\}}|dkrZtd|jdj||f|S)zCall ipset with argscSsg|] }d|qS)z%sr).0itemrrr Rszipset.__run..z %s: %s %s rz'%s %s' failed: %s)rdebug2 __class__rjoinr ValueError)rargsZ_argsstatusretrrrZ__runOsz ipset.__runcCs t|tkrttjd|dS)zCheck ipset namezipset name '%s' is not validN)lenIPSET_MAXNAMELENrrZ INVALID_NAME)rrrrr check_nameZs zipset.check_namecCsg}d}y|jdg}Wn0tk rH}ztjd|WYdd}~XnX|j}d}xT|D]L}|r|jjdd}|d|kr|dtkr|j|d|j dr\d }q\W|S) z?Return types that are supported by the ipset command and kernelz--helpzipset error: %sNFrzSupported set types:T) _ipset__runrrZdebug1 splitlinesstripsplit IPSET_TYPESappend startswith)rr"outputZexlinesZin_typeslinesplitsrrrset_supported_types`s    zipset.set_supported_typescCs(t|tks|tkr$ttjd|dS)zCheck ipset typez!ipset type name '%s' is not validN)r#r$r,rrZ INVALID_TYPE)r type_namerrr check_typeuszipset.check_typeNcCsd|j||j|d||g}t|trZx0|jD]$\}}|j||dkr2|j|q2W|j|S)z+Create an ipset with name, type and optionscreater&)r%r5 isinstancedictitemsr-r()rset_namer4optionsr keyvalrrr set_create{s     zipset.set_createcCs|j||jd|gS)NZdestroy)r%r()rr:rrr set_destroys zipset.set_destroycCsd||g}|j|S)Nadd)r()rr:entryr rrrset_adds z ipset.set_addcCsd||g}|j|S)Ndel)r()rr:rAr rrr set_deletes zipset.set_deletecCs,d||g}|r"|jddj||j|S)Ntestz%sr)r-rr()rr:rAr;r rrrrEs z ipset.testcCs2dg}|r|j||r"|j||j|jdS)Nlist )r-extendr(r+)rr:r;r rrrset_lists   zipset.set_listc Cs<|jdgd}i}d}}i}x|D] }t|dkr:q&dd|jddD}t|dkr`q&q&|d d krv|d}q&|d d kr|d}q&|d d kr&|dj}d } x^| t|kr|| } | dkrt|| kr| d7} || || <ntjd|iS| d7} qW|r$|r$|t|f||<d}}|jq&W|S)z" Get active ipsets (only headers) z-terse)r;NcSsg|] }|jqSr)r*)rxrrrrsz.ipset.set_get_active_terse..:r'rNameZTypeZHeaderrrrrnetmaskz&Malformed ipset list -terse output: %s)rrrrrN)rIr#r+rerrorrclear) rr0r"_nameZ_type_optionsr1Zpairr2ioptrrrset_get_active_tersesD            zipset.set_get_active_tersecCsdg}|r|j||j|S)Nsave)r-r()rr:r rrrrVs z ipset.savecCs|j||j|t}d|kr*d|}d||dg}|rlx0|jD]$\}} |j|| dkrD|j| qDW|jddj||jd|xN|D]F} d| krd| } |r|jd|| dj|fq|jd || fqW|jtj |j } t j d |j |jd |j | jfd g}t|j||j d \} } t jdkryt|j Wntk r`YnVXd}xNt|j D]@}t jd||fddd|jdst jddd|d7}qrWtj|j | dkrtd|jdj|| f| S)Nrz'%s'r6z-existr&z%s z flush %s z add %s %s %s z add %s %s z%s: %s restore %sz%s: %dZrestore)stdinr'rJz%8d: %sr)nofmtnlrG)rXz'%s %s' failed: %s)r%r5r r9r-writercloseosstatrrrrrst_sizerZgetDebugLogLevelr ExceptionZdebug3endswithunlinkr)rr:r4entriesZcreate_optionsZ entry_optionsZ temp_filer r<r=rAr]r!r"rSr1rrr set_restoresV         zipset.set_restorecCsdg}|r|j||j|S)Nflush)r-r()rr:r rrr set_flushs zipset.set_flushcCs|jd||gS)Nrename)r()rZ old_set_nameZ new_set_namerrrrf sz ipset.renamecCs|jd||gS)Nswap)r()rZ set_name_1Z set_name_2rrrrgsz ipset.swapcCs |jdgS)Nversion)r()rrrrrhsz ipset.version)N)N)NN)N)NN)__name__ __module__ __qualname____doc__rr(r%r3r5r>r?rBrDrErIrUrVrcrerfrgrhrrrrrHs&    '  7cCst|tkrdSdS)z"Return true if ipset name is validFT)r#r$)rrrrrs cCs8|j}x*tD]"}||krt|||kr||=qW|S)z( Return only non default create options )copyIPSET_DEFAULT_CREATE_OPTIONS)r;rRrTrrrrs   c Cshg}xX|jdD]J}y&|jd|jttj|ddWqtk rX|j|YqXqWdj|S)z! Normalize IP addresses in entry ,/F)strict)r+indexr-str ipaddress ip_networkrr)rAZ_entryZ_partrrrnormalize_ipset_entry&s rvcCsxt|jddkrdSytj|dd}Wntk r<dSXx4|D],}|jtj|ddrDttjdj ||qDWdS)z: Check if entry overlaps any entry in the list of entries rorJNF)rqz,Entry '{}' overlaps with existing entry '{}') r#r+rtruroverlapsrr INVALID_ENTRYformat)rArbZ entry_networkZitrrrrcheck_entry_overlaps_existing2s rzcCs~ydd|D}Wntk r&dSXt|dkr8dS|j|jd}x.|D]&}|j|rrttjdj|||}qPWdS)z> Check if any entry overlaps any entry in the list of entries cSsg|]}tj|ddqS)F)rq)rtru)rrKrrrrEsz1check_for_overlapping_entries..NrzEntry '{}' overlaps entry '{}') rr#sortpoprwrrrxry)rbZ prev_networkZcurrent_networkrrrcheck_for_overlapping_entriesBs 2   r})rl__all__Zos.pathr\rtZfirewallrZfirewall.errorsrZfirewall.core.progrZfirewall.core.loggerrZfirewall.functionsr r Zfirewall.configr r$r,ZIPSET_CREATE_OPTIONSrnobjectrrrrvrzr}rrrrsF      P  PKpge[zz%__pycache__/base.cpython-36.opt-1.pycnu[3 g6@sdZdZdZd0ZdddedgZddddgZd d d d d ddZddddddddddddddddgd d!d"d#d$d%d&ddg d'Zd(d)d*d+d,d-d.gZd/S)1zBase firewall settingsz{chain}_{zone}ZCONTINUEZACCEPTz %%REJECT%%ZDROPdefaultZREJECTZPREZPOSTINZFWDIZFWDOZOUT)Z PREROUTINGZ POSTROUTINGZINPUTZ FORWARD_INZ FORWARD_OUTZOUTPUTzicmp-host-prohibitedz host-prohibzicmp-net-unreachablez net-unreachzicmp-host-unreachablez host-unreachzicmp-port-unreachablez port-unreachzicmp-proto-unreachablez proto-unreachzicmp-net-prohibitedz net-prohibz tcp-resetztcp-rstzicmp-admin-prohibitedz admin-prohibzicmp6-adm-prohibitedzadm-prohibitedzicmp6-no-routezno-routezicmp6-addr-unreachablez addr-unreachzicmp6-port-unreachable)Zipv4Zipv6zhash:ipz hash:ip,portz hash:ip,markzhash:netz hash:net,portzhash:net,ifacezhash:macN) __doc__ZDEFAULT_ZONE_TARGETZDEFAULT_POLICY_TARGETZDEFAULT_POLICY_PRIORITYZ ZONE_TARGETSZPOLICY_TARGETSZ SHORTCUTSZ REJECT_TYPESZSOURCE_IPSET_TYPESrr/usr/lib/python3.6/base.pys. PKpge[3]Z]Z'__pycache__/logger.cpython-36.opt-1.pycnu[3 g>y@sddddgZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z Gddde Z Gddde Z Gd d d e ZGd d d e ZGd dde ZGddde ZeZdS) LogTargetFileLogLoggerlogNc@s2eZdZdZddZd ddZddZd d Zd S) rz% Abstract class for logging targets. cCs d|_dS)N)fd)selfr/usr/lib/python3.6/logger.py__init__(szLogTarget.__init__rcCs tddS)Nz%LogTarget.write is an abstract method)NotImplementedError)rdatalevelloggeris_debugrrr write+szLogTarget.writecCs tddS)Nz%LogTarget.flush is an abstract method)r )rrrr flush.szLogTarget.flushcCs tddS)Nz%LogTarget.close is an abstract method)r )rrrr close1szLogTarget.closeN)r)__name__ __module__ __qualname____doc__r rrrrrrr r&s  c@s.eZdZddZd ddZddZdd Zd S) _StdoutLogcCstj|tj|_dS)N)rr sysstdoutr)rrrr r 8s z_StdoutLog.__init__rcCs|jj||jdS)N)rrr)rr r rrrrr r<s z_StdoutLog.writecCs |jdS)N)r)rrrr rAsz_StdoutLog.closecCs|jjdS)N)rr)rrrr rDsz_StdoutLog.flushN)r)rrrr rrrrrrr r7s rc@seZdZddZdS) _StderrLogcCstj|tj|_dS)N)rr rstderrr)rrrr r Ks z_StderrLog.__init__N)rrrr rrrr rJsrc@s.eZdZddZd ddZddZdd Zd S) _SyslogLogcCs.tj|tjtjjtjdtj tj dS)Nr) rr syslogZopenlogospathbasenamerargvZLOG_PIDZ LOG_DAEMON)rrrr r Ss z_SyslogLog.__init__rcCsd}|rtj}nF||jkr"tj}n4||jkr4tj}n"||jkrFtj}n||jkrVtj }|j drt|dt |d}t |dkr|dkrtj|n tj||dS)N r) rZ LOG_DEBUGINFO1ZLOG_INFOWARNINGZ LOG_WARNINGERRORZLOG_ERRFATALZLOG_CRITendswithlen)rr r rrZpriorityrrr ras"       z_SyslogLog.writecCs tjdS)N)rZcloselog)rrrr rwsz_SyslogLog.closecCsdS)Nr)rrrr rzsz_SyslogLog.flushN)r)rrrr rrrrrrr rRs rc@s<eZdZdZdddZddZddd Zd d Zd d ZdS)rz< FileLog class. File will be opened on the first write. wcCstj|||_||_dS)N)rr filenamemode)rr+r,rrr r s zFileLog.__init__cCsv|jr dStjtjB}|jjdr,|tjO}tj|j|d|_tj |jdtj |j|j|_t j |jt j t j dS)Nai)rrO_CREATO_WRONLYr, startswithO_APPENDopenr+fchmodfdopenfcntlZF_SETFDZ FD_CLOEXEC)rflagsrrr r2s   z FileLog.openrcCs(|js|j|jj||jjdS)N)rr2rr)rr r rrrrr rs z FileLog.writecCs|js dS|jjd|_dS)N)rr)rrrr rs z FileLog.closecCs|js dS|jjdS)N)rr)rrrr rsz FileLog.flushN)r*)r) rrrrr r2rrrrrrr rs   c@seZdZdZd[Zd\Zd]Zd^Zd_ZdZ e Z e Z eZd`d d Zd d ZdaddZdbddZdcddZddddZddZddZddZddZddZd d!Zed"fd#d$Zed"fd%d&Zed"fd'd(Zed"fd)d*Zed"fd+d,Z ed"fd-d.Z!d/d0Z"d1d2Z#d3d4Z$d5d6Z%d7d8Z&d9d:Z'd;d<Z(d=d>Z)d?d@Z*dAdBZ+dCdDZ,dedEdFZ-dGdHZ.dfdIdJZ/ed"dfdKdLZ0ed"dfdMdNZ1ed"dfdOdPZ2dgdQdRZ3dSdTZ4dUdVZ5dWdXZ6dhdYdZZ7d"S)iraL Format string: %(class)s Calling class the function belongs to, else empty %(date)s Date using Logger.date_format, see time module %(domain)s Full Domain: %(module)s.%(class)s.%(function)s %(file)s Filename of the module %(function)s Function name, empty in __main__ %(label)s Label according to log function call from Logger.label %(level)d Internal logging level %(line)d Line number in module %(module)s Module name %(message)s Log message Standard levels: FATAL Fatal error messages ERROR Error messages WARNING Warning messages INFOx, x in [1..5] Information DEBUGy, y in [1..10] Debug messages NO_INFO No info output NO_DEBUG No debug output INFO_MAX Maximum info level DEBUG_MAX Maximum debug level x and y depend on info_max and debug_max from Logger class initialization. See __init__ function. Default logging targets: stdout Logs to stdout stderr Logs to stderr syslog Logs to syslog Additional arguments for logging functions (fatal, error, warning, info and debug): nl Disable newline at the end with nl=0, default is nl=1. fmt Format string for this logging entry, overloads global format string. Example: fmt="%(file)s:%(line)d %(message)s" nofmt Only output message with nofmt=1. The nofmt argument wins over the fmt argument. Example: from logger import log log.setInfoLogLevel(log.INFO1) log.setDebugLogLevel(log.DEBUG1) for i in range(1, log.INFO_MAX+1): log.setInfoLogLabel(i, "INFO%d: " % i) log.setFormat("%(date)s %(module)s:%(line)d [%(domain)s] %(label)s: " "%(level)d %(message)s") log.setDateFormat("%Y-%m-%d %H:%M:%S") fl = FileLog("/tmp/log", "a") log.addInfoLogging("*", fl) log.addDebugLogging("*", fl) log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s") log.debug3("debug3") log.debug2("debug2") log.debug1("debug1") log.info2("info2") log.info1("info1") log.warning("warning\n", nl=0) log.error("error\n", nl=0) log.fatal("fatal") log.info(log.INFO1, "nofmt info", nofmt=1) r#r cCsi|_i|_d|_d|_i|_i|_i|_i|_i|_i|_ |dkrPt d||dkrdt d||j |_ ||_ d|_||_|j|jd|j|jd|j|jd|j|j dxNtd|j dD]:}t|d |||j|dt|d |d d ||qWxTtd|jdD]@}t|d |||j|d|t|d|dd ||qW|j|j|j|j|jd|jd|jd|j|j|j|j g|jd|jddt|j|j dD|jd|jddtd|jdDdS)z Logger class initialization r#zLogger: info_max %d is too lowrzLogger: debug_max %d is too lowz FATAL ERROR: zERROR: z WARNING: zINFO%dzinfo%dcsfddS)Ncsj|f||S)N)info)messageargskwargs)rxrr  sz3Logger.__init__....r)rrAr)rrAr rBsz!Logger.__init__..zDEBUG%dz DEBUG%d: zdebug%dcsfddS)Ncsj|f||S)N)debug)r>r?r@)rrArr rB)sz3Logger.__init__....r)rrAr)rrAr rB(sz%(label)s%(message)sz%d %b %Y %H:%M:%S*cSsg|]}|qSrr).0irrr 4sz#Logger.__init__..cSsg|]}|qSrr)rErFrrr rG6sN) _level _debug_level_format _date_format_label _debug_label_logging_debug_logging_domains_debug_domains ValueErrorr%NO_INFOINFO_MAXNO_DEBUG DEBUG_MAXsetInfoLogLabelr' TRACEBACKr&rangesetattrsetDebugLogLabelsetInfoLogLevelr$setDebugLogLevel setFormat setDateFormatsetInfoLoggingrrsetDebugLogging)rZinfo_maxZ debug_maxrHrrr r sX            zLogger.__init__cCsNxHt|j|jdD]2}||jkr$qx |j|D]\}}}|jq0WqWdS)z Close all logging targets r#N)rYr'rVrNr)rr dummytargetrrr r8s  z Logger.closerDcCs$|j|||jkr|j|S|jS)z Get info log level. ) _checkDomainrHNOTHING)rdomainrrr getInfoLogLevel@s   zLogger.getInfoLogLevelcCs8|j|||jkr|j}||jkr*|j}||j|<dS)z% Set log level [NOTHING .. INFO_MAX] N)rdrerTrH)rr rfrrr r\Gs    zLogger.setInfoLogLevelcCs*|j|||jkr$|j||jS|jS)z Get debug log level. )rdrIrU)rrfrrr getDebugLogLevelPs  zLogger.getDebugLogLevelcCs:|j||dkrd}||jkr&|j}||j|j|<dS)z- Set debug log level [NO_DEBUG .. DEBUG_MAX] rN)rdrVrUrI)rr rfrrr r]Ws   zLogger.setDebugLogLevelcCs|jS)N)rJ)rrrr getFormat`szLogger.getFormatcCs ||_dS)N)rJ)rrJrrr r^cszLogger.setFormatcCs|jS)N)rK)rrrr getDateFormatfszLogger.getDateFormatcCs ||_dS)N)rK)rrJrrr r_iszLogger.setDateFormatcCs:|j|}x*|D]"}|j||j|jd||j|<qWdS)zU Set log label for level. Level can be a single level or an array of levels. ) min_level max_levelN) _getLevels_checkLogLevelr'rTrL)rr labellevelsrrr rWls     zLogger.setInfoLogLabelcCs>|j|dd}x*|D]"}|j||j|jd||j|<qWdS)zU Set log label for level. Level can be a single level or an array of levels. r#)r)rkrlN)rmrnr$rVrM)rr rorprrr r[us    zLogger.setDebugLogLabelNcCs|j||||dddS)z Set info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r)rN) _setLogging)rrfrcr fmtrrr r`~szLogger.setInfoLoggingcCs|j||||dddS)z Set debug log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r#)rN)rq)rrfrcr rrrrr raszLogger.setDebugLoggingcCs|j||||dddS)z Add info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r)rN) _addLogging)rrfrcr rrrrr addInfoLoggingszLogger.addInfoLoggingcCs|j||||dddS)z Add debg log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r#)rN)rs)rrfrcr rrrrr addDebugLoggingszLogger.addDebugLoggingcCs|j||||dddS)z Delete info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r)rN) _delLogging)rrfrcr rrrrr delInfoLoggingszLogger.delInfoLoggingcCs|j||||dddS)z Delete debug log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r#)rN)rv)rrfrcr rrrrr delDebugLoggingszLogger.delDebugLoggingcCs|j|ddS)zN Is there currently any info logging for this log level (and domain)? r)r)_isLoggingHere)rr rrr isInfoLoggingHereszLogger.isInfoLoggingHerecCs|j|ddS)zO Is there currently any debug logging for this log level (and domain)? r#)r)ry)rr rrr isDebugLoggingHereszLogger.isDebugLoggingHerecOs,|j|d|d<|j|j|f||dS)z Fatal error log. rrN) _checkKWargs_logr')rrJr?r@rrr fatals z Logger.fatalcOs,|j|d|d<|j|j|f||dS)z Error log. rrN)r|r}r&)rrJr?r@rrr errors z Logger.errorcOs,|j|d|d<|j|j|f||dS)z Warning log. rrN)r|r}r%)rrJr?r@rrr warnings zLogger.warningcOsB|j|d|jd|j|d|d<|j||j|f||dS)z Information log using info level [1..info_max]. There are additional infox functions according to info_max from __init__r#)rkrlrrN)rnrTr|r}rS)rr rJr?r@rrr r=s z Logger.infocOs<|j|d|jd|j|d|d<|j||f||dS)z Debug log using debug level [1..debug_max]. There are additional debugx functions according to debug_max from __init__r#)rkrlrN)rnrVr|r})rr rJr?r@rrr rCs z Logger.debugcCs|j|jtjgiddS)N)r?r@)r}rX traceback format_exc)rrrr exceptionszLogger.exceptioncCs&||ks||kr"td|||fdS)Nz*Level %d out of range, should be [%d..%d].)rR)rr rkrlrrr rnszLogger._checkLogLevelcCs2|sdSx$|jD]}|dkrtd|qWdS)Nnlrrnofmtz0Key '%s' is not allowed as argument for logging.)rrrr)keysrR)rr@keyrrr r|s zLogger._checkKWargscCs| s|dkrtd|dS)Nr<zDomain '%s' is not valid.)rR)rrfrrr rdszLogger._checkDomaincCs||jkrft|tst|tr$|}n|g}xp|D]0}|rL|j|d|jdq0|j||j|jdq0Wn6|rddt|j |jD}nddt|j|jD}|S)z Generate log level array. r#)rkrlcSsg|]}|qSrr)rErFrrr rGsz%Logger._getLevels..cSsg|]}|qSrr)rErFrrr rGs) ALL isinstancelisttuplernrVr'rTrYZDEBUG1)rr rrprrr rms    zLogger._getLevelscCsNt|tst|tr|}n|g}x(|D] }t|jts&td|jjq&W|S)z Generate target array. z '%s' is no valid logging target.)rrr issubclass __class__rrRr)rrctargetsZ_targetrrr _getTargetss  zLogger._getTargetscCs|r |j}|j}d|jdf}n|j}|j}|j|jdf}t|dkrP|jxVt |d|dD]@}||krrqdx0||D]$\}}}||kr||j |gj |q|WqdWdS)z% Generate dict with domain by level. r#rN) rQrOrVrPrNr'rTr)clearrY setdefaultappend)rrrPrNZ_ranger rfrbrrr _genDomainss zLogger._genDomainsc Csl|j||j||}|j|}|r,|j}n|j}x*|D]"}x|D]}|||fg||<qBWq8W|j|dS)N)rdrmrrOrNr) rrfrcr rrrrprrNrrr rqs     zLogger._setLoggingc Cst|j||j||}|j|}|r,|j}n|j}x2|D]*}x$|D]}|j|gj|||fqBWq8W|j|dS)N)rdrmrrOrNrrr) rrfrcr rrrrprrNrrr rs-s      zLogger._addLoggingc Cs|j||j||}|j|}|r,|j}n|j}x|D]|} xv|D]n}| |krPqB|||f|| kr|| j|||ft|| dkr|| =qB||jkrBtd| ||j j |fqBWq8W|j |dS)NrzDNo mathing logging for level %d, domain %s, target %s and format %s.) rdrmrrOrNremover)rrRrrr) rrfrcr rrrrprrNrHrrr rv<s&      zLogger._delLoggingcCst|j||}|sdS|dd}|r,|j}n|j}x<||D]0\}}}|dksh|j|shtj|d|rrfrrDrrr") rr)rOrNr0rrrJrr)rr rJr?r@rrrrrrNZ used_targetsrfrcrrr r}sL     z Logger._logc Csg}d}|r |j}|j}|j}n|j}|j}|j}xN|D]F}|dkrh|||kr~d}t|dkrdg}Pq8|||kr8|j|q8W| rt|dkrdS||krdStj } x$| r| j r| j d|j kr| j } qW| st d| j d} | d } x|D]}| j|rg}PqW| j} t| } xx||D]l}|jd}|dkrDq&n|dkr\|d|}n|}| t|kr| j|sdSn|j| s&dSq&Wd }||kr||}| j| j| d | jd ||tj|jtjd }|d d krd |d <d}x&||D]}|dkrqd}PqW|jjddksR|jjddksR|sRt|dkrl|j| }|rl|j|d<d |d|d<|dd kr|dd |d7<|d d kr|dd |d 7<t|dkr|S|dd }x0|D](}|j|stj|d|r|SqWdS)z Internal function. FrDTrr#Nrz Frame information not available.rr<) filelinerclassfunctionrfror Zdater?z %(domain)z%(class)rrrf)rIrQrMrHrPrLr)rrZ currentframef_back f_globalsrrRr0rfind co_filenamef_linenortimeZstrftimerKZ localtimerJrrrr)rr rZ check_domainsZ simple_matchrrPrLrffZ module_nameZ point_moduleco_lenrFdZ level_strZ domain_neededrrrrr rs                      zLogger._genDict)r7r;)rD)rD)rD)rD)r)r)r)r)8rrrrrrer'rXr&r%rrrrrrr rrgr\rhr]rir^rjr_rWr[r`rartrurwrxrzr{r~rrr=rCrrnr|rdrmrrrqrsrvryrrr}rrrrr rsdG ;           4)__all__rrrrrrrr5Zos.pathrobjectrrrrrrrrrrr s. -(*4PKpge[B!__pycache__/helper.cpython-36.pycnu[3 g$@s dZdZdS)zThe helper maxnamelen N)__doc__ZHELPER_MAXNAMELENrr/usr/lib/python3.6/helper.pysPKpge[3]Z]Z!__pycache__/logger.cpython-36.pycnu[3 g>y@sddddgZddlZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z Gddde Z Gddde Z Gd d d e ZGd d d e ZGd dde ZGddde ZeZdS) LogTargetFileLogLoggerlogNc@s2eZdZdZddZd ddZddZd d Zd S) rz% Abstract class for logging targets. cCs d|_dS)N)fd)selfr/usr/lib/python3.6/logger.py__init__(szLogTarget.__init__rcCs tddS)Nz%LogTarget.write is an abstract method)NotImplementedError)rdatalevelloggeris_debugrrr write+szLogTarget.writecCs tddS)Nz%LogTarget.flush is an abstract method)r )rrrr flush.szLogTarget.flushcCs tddS)Nz%LogTarget.close is an abstract method)r )rrrr close1szLogTarget.closeN)r)__name__ __module__ __qualname____doc__r rrrrrrr r&s  c@s.eZdZddZd ddZddZdd Zd S) _StdoutLogcCstj|tj|_dS)N)rr sysstdoutr)rrrr r 8s z_StdoutLog.__init__rcCs|jj||jdS)N)rrr)rr r rrrrr r<s z_StdoutLog.writecCs |jdS)N)r)rrrr rAsz_StdoutLog.closecCs|jjdS)N)rr)rrrr rDsz_StdoutLog.flushN)r)rrrr rrrrrrr r7s rc@seZdZddZdS) _StderrLogcCstj|tj|_dS)N)rr rstderrr)rrrr r Ks z_StderrLog.__init__N)rrrr rrrr rJsrc@s.eZdZddZd ddZddZdd Zd S) _SyslogLogcCs.tj|tjtjjtjdtj tj dS)Nr) rr syslogZopenlogospathbasenamerargvZLOG_PIDZ LOG_DAEMON)rrrr r Ss z_SyslogLog.__init__rcCsd}|rtj}nF||jkr"tj}n4||jkr4tj}n"||jkrFtj}n||jkrVtj }|j drt|dt |d}t |dkr|dkrtj|n tj||dS)N r) rZ LOG_DEBUGINFO1ZLOG_INFOWARNINGZ LOG_WARNINGERRORZLOG_ERRFATALZLOG_CRITendswithlen)rr r rrZpriorityrrr ras"       z_SyslogLog.writecCs tjdS)N)rZcloselog)rrrr rwsz_SyslogLog.closecCsdS)Nr)rrrr rzsz_SyslogLog.flushN)r)rrrr rrrrrrr rRs rc@s<eZdZdZdddZddZddd Zd d Zd d ZdS)rz< FileLog class. File will be opened on the first write. wcCstj|||_||_dS)N)rr filenamemode)rr+r,rrr r s zFileLog.__init__cCsv|jr dStjtjB}|jjdr,|tjO}tj|j|d|_tj |jdtj |j|j|_t j |jt j t j dS)Nai)rrO_CREATO_WRONLYr, startswithO_APPENDopenr+fchmodfdopenfcntlZF_SETFDZ FD_CLOEXEC)rflagsrrr r2s   z FileLog.openrcCs(|js|j|jj||jjdS)N)rr2rr)rr r rrrrr rs z FileLog.writecCs|js dS|jjd|_dS)N)rr)rrrr rs z FileLog.closecCs|js dS|jjdS)N)rr)rrrr rsz FileLog.flushN)r*)r) rrrrr r2rrrrrrr rs   c@seZdZdZd[Zd\Zd]Zd^Zd_ZdZ e Z e Z eZd`d d Zd d ZdaddZdbddZdcddZddddZddZddZddZddZddZd d!Zed"fd#d$Zed"fd%d&Zed"fd'd(Zed"fd)d*Zed"fd+d,Z ed"fd-d.Z!d/d0Z"d1d2Z#d3d4Z$d5d6Z%d7d8Z&d9d:Z'd;d<Z(d=d>Z)d?d@Z*dAdBZ+dCdDZ,dedEdFZ-dGdHZ.dfdIdJZ/ed"dfdKdLZ0ed"dfdMdNZ1ed"dfdOdPZ2dgdQdRZ3dSdTZ4dUdVZ5dWdXZ6dhdYdZZ7d"S)iraL Format string: %(class)s Calling class the function belongs to, else empty %(date)s Date using Logger.date_format, see time module %(domain)s Full Domain: %(module)s.%(class)s.%(function)s %(file)s Filename of the module %(function)s Function name, empty in __main__ %(label)s Label according to log function call from Logger.label %(level)d Internal logging level %(line)d Line number in module %(module)s Module name %(message)s Log message Standard levels: FATAL Fatal error messages ERROR Error messages WARNING Warning messages INFOx, x in [1..5] Information DEBUGy, y in [1..10] Debug messages NO_INFO No info output NO_DEBUG No debug output INFO_MAX Maximum info level DEBUG_MAX Maximum debug level x and y depend on info_max and debug_max from Logger class initialization. See __init__ function. Default logging targets: stdout Logs to stdout stderr Logs to stderr syslog Logs to syslog Additional arguments for logging functions (fatal, error, warning, info and debug): nl Disable newline at the end with nl=0, default is nl=1. fmt Format string for this logging entry, overloads global format string. Example: fmt="%(file)s:%(line)d %(message)s" nofmt Only output message with nofmt=1. The nofmt argument wins over the fmt argument. Example: from logger import log log.setInfoLogLevel(log.INFO1) log.setDebugLogLevel(log.DEBUG1) for i in range(1, log.INFO_MAX+1): log.setInfoLogLabel(i, "INFO%d: " % i) log.setFormat("%(date)s %(module)s:%(line)d [%(domain)s] %(label)s: " "%(level)d %(message)s") log.setDateFormat("%Y-%m-%d %H:%M:%S") fl = FileLog("/tmp/log", "a") log.addInfoLogging("*", fl) log.addDebugLogging("*", fl) log.addInfoLogging("*", log.syslog, fmt="%(label)s%(message)s") log.debug3("debug3") log.debug2("debug2") log.debug1("debug1") log.info2("info2") log.info1("info1") log.warning("warning\n", nl=0) log.error("error\n", nl=0) log.fatal("fatal") log.info(log.INFO1, "nofmt info", nofmt=1) r#r cCsi|_i|_d|_d|_i|_i|_i|_i|_i|_i|_ |dkrPt d||dkrdt d||j |_ ||_ d|_||_|j|jd|j|jd|j|jd|j|j dxNtd|j dD]:}t|d |||j|dt|d |d d ||qWxTtd|jdD]@}t|d |||j|d|t|d|dd ||qW|j|j|j|j|jd|jd|jd|j|j|j|j g|jd|jddt|j|j dD|jd|jddtd|jdDdS)z Logger class initialization r#zLogger: info_max %d is too lowrzLogger: debug_max %d is too lowz FATAL ERROR: zERROR: z WARNING: zINFO%dzinfo%dcsfddS)Ncsj|f||S)N)info)messageargskwargs)rxrr  sz3Logger.__init__....r)rrAr)rrAr rBsz!Logger.__init__..zDEBUG%dz DEBUG%d: zdebug%dcsfddS)Ncsj|f||S)N)debug)r>r?r@)rrArr rB)sz3Logger.__init__....r)rrAr)rrAr rB(sz%(label)s%(message)sz%d %b %Y %H:%M:%S*cSsg|]}|qSrr).0irrr 4sz#Logger.__init__..cSsg|]}|qSrr)rErFrrr rG6sN) _level _debug_level_format _date_format_label _debug_label_logging_debug_logging_domains_debug_domains ValueErrorr%NO_INFOINFO_MAXNO_DEBUG DEBUG_MAXsetInfoLogLabelr' TRACEBACKr&rangesetattrsetDebugLogLabelsetInfoLogLevelr$setDebugLogLevel setFormat setDateFormatsetInfoLoggingrrsetDebugLogging)rZinfo_maxZ debug_maxrHrrr r sX            zLogger.__init__cCsNxHt|j|jdD]2}||jkr$qx |j|D]\}}}|jq0WqWdS)z Close all logging targets r#N)rYr'rVrNr)rr dummytargetrrr r8s  z Logger.closerDcCs$|j|||jkr|j|S|jS)z Get info log level. ) _checkDomainrHNOTHING)rdomainrrr getInfoLogLevel@s   zLogger.getInfoLogLevelcCs8|j|||jkr|j}||jkr*|j}||j|<dS)z% Set log level [NOTHING .. INFO_MAX] N)rdrerTrH)rr rfrrr r\Gs    zLogger.setInfoLogLevelcCs*|j|||jkr$|j||jS|jS)z Get debug log level. )rdrIrU)rrfrrr getDebugLogLevelPs  zLogger.getDebugLogLevelcCs:|j||dkrd}||jkr&|j}||j|j|<dS)z- Set debug log level [NO_DEBUG .. DEBUG_MAX] rN)rdrVrUrI)rr rfrrr r]Ws   zLogger.setDebugLogLevelcCs|jS)N)rJ)rrrr getFormat`szLogger.getFormatcCs ||_dS)N)rJ)rrJrrr r^cszLogger.setFormatcCs|jS)N)rK)rrrr getDateFormatfszLogger.getDateFormatcCs ||_dS)N)rK)rrJrrr r_iszLogger.setDateFormatcCs:|j|}x*|D]"}|j||j|jd||j|<qWdS)zU Set log label for level. Level can be a single level or an array of levels. ) min_level max_levelN) _getLevels_checkLogLevelr'rTrL)rr labellevelsrrr rWls     zLogger.setInfoLogLabelcCs>|j|dd}x*|D]"}|j||j|jd||j|<qWdS)zU Set log label for level. Level can be a single level or an array of levels. r#)r)rkrlN)rmrnr$rVrM)rr rorprrr r[us    zLogger.setDebugLogLabelNcCs|j||||dddS)z Set info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r)rN) _setLogging)rrfrcr fmtrrr r`~szLogger.setInfoLoggingcCs|j||||dddS)z Set debug log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r#)rN)rq)rrfrcr rrrrr raszLogger.setDebugLoggingcCs|j||||dddS)z Add info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r)rN) _addLogging)rrfrcr rrrrr addInfoLoggingszLogger.addInfoLoggingcCs|j||||dddS)z Add debg log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r#)rN)rs)rrfrcr rrrrr addDebugLoggingszLogger.addDebugLoggingcCs|j||||dddS)z Delete info log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r)rN) _delLogging)rrfrcr rrrrr delInfoLoggingszLogger.delInfoLoggingcCs|j||||dddS)z Delete debug log target for domain and level. Level can be a single level or an array of levels. Use level ALL to set for all levels. If no format is specified, the default format will be used. r#)rN)rv)rrfrcr rrrrr delDebugLoggingszLogger.delDebugLoggingcCs|j|ddS)zN Is there currently any info logging for this log level (and domain)? r)r)_isLoggingHere)rr rrr isInfoLoggingHereszLogger.isInfoLoggingHerecCs|j|ddS)zO Is there currently any debug logging for this log level (and domain)? r#)r)ry)rr rrr isDebugLoggingHereszLogger.isDebugLoggingHerecOs,|j|d|d<|j|j|f||dS)z Fatal error log. rrN) _checkKWargs_logr')rrJr?r@rrr fatals z Logger.fatalcOs,|j|d|d<|j|j|f||dS)z Error log. rrN)r|r}r&)rrJr?r@rrr errors z Logger.errorcOs,|j|d|d<|j|j|f||dS)z Warning log. rrN)r|r}r%)rrJr?r@rrr warnings zLogger.warningcOsB|j|d|jd|j|d|d<|j||j|f||dS)z Information log using info level [1..info_max]. There are additional infox functions according to info_max from __init__r#)rkrlrrN)rnrTr|r}rS)rr rJr?r@rrr r=s z Logger.infocOs<|j|d|jd|j|d|d<|j||f||dS)z Debug log using debug level [1..debug_max]. There are additional debugx functions according to debug_max from __init__r#)rkrlrN)rnrVr|r})rr rJr?r@rrr rCs z Logger.debugcCs|j|jtjgiddS)N)r?r@)r}rX traceback format_exc)rrrr exceptionszLogger.exceptioncCs&||ks||kr"td|||fdS)Nz*Level %d out of range, should be [%d..%d].)rR)rr rkrlrrr rnszLogger._checkLogLevelcCs2|sdSx$|jD]}|dkrtd|qWdS)Nnlrrnofmtz0Key '%s' is not allowed as argument for logging.)rrrr)keysrR)rr@keyrrr r|s zLogger._checkKWargscCs| s|dkrtd|dS)Nr<zDomain '%s' is not valid.)rR)rrfrrr rdszLogger._checkDomaincCs||jkrft|tst|tr$|}n|g}xp|D]0}|rL|j|d|jdq0|j||j|jdq0Wn6|rddt|j |jD}nddt|j|jD}|S)z Generate log level array. r#)rkrlcSsg|]}|qSrr)rErFrrr rGsz%Logger._getLevels..cSsg|]}|qSrr)rErFrrr rGs) ALL isinstancelisttuplernrVr'rTrYZDEBUG1)rr rrprrr rms    zLogger._getLevelscCsNt|tst|tr|}n|g}x(|D] }t|jts&td|jjq&W|S)z Generate target array. z '%s' is no valid logging target.)rrr issubclass __class__rrRr)rrctargetsZ_targetrrr _getTargetss  zLogger._getTargetscCs|r |j}|j}d|jdf}n|j}|j}|j|jdf}t|dkrP|jxVt |d|dD]@}||krrqdx0||D]$\}}}||kr||j |gj |q|WqdWdS)z% Generate dict with domain by level. r#rN) rQrOrVrPrNr'rTr)clearrY setdefaultappend)rrrPrNZ_ranger rfrbrrr _genDomainss zLogger._genDomainsc Csl|j||j||}|j|}|r,|j}n|j}x*|D]"}x|D]}|||fg||<qBWq8W|j|dS)N)rdrmrrOrNr) rrfrcr rrrrprrNrrr rqs     zLogger._setLoggingc Cst|j||j||}|j|}|r,|j}n|j}x2|D]*}x$|D]}|j|gj|||fqBWq8W|j|dS)N)rdrmrrOrNrrr) rrfrcr rrrrprrNrrr rs-s      zLogger._addLoggingc Cs|j||j||}|j|}|r,|j}n|j}x|D]|} xv|D]n}| |krPqB|||f|| kr|| j|||ft|| dkr|| =qB||jkrBtd| ||j j |fqBWq8W|j |dS)NrzDNo mathing logging for level %d, domain %s, target %s and format %s.) rdrmrrOrNremover)rrRrrr) rrfrcr rrrrprrNrHrrr rv<s&      zLogger._delLoggingcCst|j||}|sdS|dd}|r,|j}n|j}x<||D]0\}}}|dksh|j|shtj|d|rrfrrDrrr") rr)rOrNr0rrrJrr)rr rJr?r@rrrrrrNZ used_targetsrfrcrrr r}sL     z Logger._logc Csg}d}|r |j}|j}|j}n|j}|j}|j}xN|D]F}|dkrh|||kr~d}t|dkrdg}Pq8|||kr8|j|q8W| rt|dkrdS||krdStj } x$| r| j r| j d|j kr| j } qW| st d| j d} | d } x|D]}| j|rg}PqW| j} t| } xx||D]l}|jd}|dkrDq&n|dkr\|d|}n|}| t|kr| j|sdSn|j| s&dSq&Wd }||kr||}| j| j| d | jd ||tj|jtjd }|d d krd |d <d}x&||D]}|dkrqd}PqW|jjddksR|jjddksR|sRt|dkrl|j| }|rl|j|d<d |d|d<|dd kr|dd |d7<|d d kr|dd |d 7<t|dkr|S|dd }x0|D](}|j|stj|d|r|SqWdS)z Internal function. FrDTrr#Nrz Frame information not available.rr<) filelinerclassfunctionrfror Zdater?z %(domain)z%(class)rrrf)rIrQrMrHrPrLr)rrZ currentframef_back f_globalsrrRr0rfind co_filenamef_linenortimeZstrftimerKZ localtimerJrrrr)rr rZ check_domainsZ simple_matchrrPrLrffZ module_nameZ point_moduleco_lenrFdZ level_strZ domain_neededrrrrr rs                      zLogger._genDict)r7r;)rD)rD)rD)rD)r)r)r)r)8rrrrrrer'rXr&r%rrrrrrr rrgr\rhr]rir^rjr_rWr[r`rartrurwrxrzr{r~rrr=rCrrnr|rdrmrrrqrsrvryrrr}rrrrr rsdG ;           4)__all__rrrrrrrr5Zos.pathrobjectrrrrrrrrrrr s. -(*4PKpge[0__pycache__/prog.cpython-36.pycnu[3 g@sddlZdgZdddZdS)NrunProgc Cs|dkr g}|g|}d}|r@t|d}|jj}WdQRXddi}y tj|tjtjtjd|d}Wntk r|d SX|j|\}} |j dd }|j |fS) NrZLANGCT)stdinstderrstdoutZ close_fdsenvzutf-8replace)r r ) openreadencode subprocessPopenPIPEZSTDOUTOSErrorZ communicatedecode returncode) progargvrargsZ input_stringZhandlerZprocessoutputZ err_outputr/usr/lib/python3.6/prog.pyrs$    )NN)r__all__rrrrrsPKpge[:ےII*__pycache__/fw_policy.cpython-36.opt-1.pycnu[3 g=V@sddlZddlZddlmZddlmZmZmZmZm Z m Z m Z m Z m Z mZddlmZmZmZmZmZmZmZmZmZmZmZddlmZddlmZddlm Z ddl!m"Z"dd l#m$Z$Gd d d e%Z&dS) N)log) portStr checkIPnMask checkIP6nMask checkProtocolenable_ip_forwardingcheck_single_addressportInPortRangeget_nf_conntrack_short_namecoalescePortRangebreakPortRange) Rich_Rule Rich_Accept Rich_Service Rich_Port Rich_ProtocolRich_MasqueradeRich_ForwardPortRich_SourcePortRich_IcmpBlock Rich_IcmpType Rich_Mark)FirewallTransaction)errors) FirewallError)LastUpdatedOrderedDict)SOURCE_IPSET_TYPESc@seZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ d ddZddZddZddZd d d!Zd d"d#Zdd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zdd0d1Zd2d3Zdd4d5Zd6d7Zd8d9Zd:d;Zdd?Z dd@dAZ!dBdCZ"ddDdEZ#dFdGZ$dHdIZ%dJdKZ&dLdMZ'dNdOZ(dPdQZ)dRdSZ*ddTdUZ+dVdWZ,ddXdYZ-dZd[Z.d\d]Z/d^d_Z0d`daZ1dbdcZ2ddddeZ3dfdgZ4ddhdiZ5djdkZ6dldmZ7dndoZ8dpdqZ9drdsZ:dtduZ;dvdwZ<ddxdyZ=dzd{Z>dd|d}Z?d~dZ@ddZAddZBddZCddZDdddZEddZFdddZGddZHddZIddZJddZKdddZLddZMdddZNddZOddZPddZQddZRdddZSddZTdddZUddZVddZWdddZXd ddZYd!ddZZddZ[d"ddZ\ddZ]d#ddZ^ddZ_ddZ`ddZad$ddÄZbddńZcd%ddDŽZdddɄZedd˄Zfdd̈́ZgddτZhd&ddфZiddӄZjddՄZkd'ddׄZlddلZmddۄZndd݄Zodd߄ZpddZqddZrddZsddZtddZud(ddZvd)ddZwddZxddZyddZzddZ{d*ddZ|ddZ}ddZ~ddZddZddZddZddZddZd+d d ZdS(,FirewallPolicycCs||_i|_i|_dS)N)_fw_chains _policies)selffwr#/usr/lib/python3.6/fw_policy.py__init__szFirewallPolicy.__init__cCsd|j|j|jfS)Nz %s(%r, %r)) __class__rr )r!r#r#r$__repr__szFirewallPolicy.__repr__cCs|jj|jjdS)N)rclearr )r!r#r#r$cleanups zFirewallPolicy.cleanupcCs t|jS)N)rr)r!r#r#r$new_transaction$szFirewallPolicy.new_transactioncCst|jjS)N)sortedr keys)r!r#r#r$ get_policies)szFirewallPolicy.get_policiescCs8g}x*|jD]}|j|}|js|j|qWt|S)N)r- get_policyderived_from_zoneappendr+)r!Zpoliciespp_objr#r#r$"get_policies_not_derived_from_zone,s  z1FirewallPolicy.get_policies_not_derived_from_zonecCs~g}xt|jD]h}|j|}t|dt|jjjtddgB@rt|dt|jjjtddgB@r|j|qW|S)N ingress_zonesHOSTANY egress_zones)r3 get_settingssetrzoneZget_active_zonesr0)r!Zactive_policiespolicysettingsr#r#r$)get_active_policies_not_derived_from_zone4s ((z8FirewallPolicy.get_active_policies_not_derived_from_zonecCs|jj|}|j|S)N)r check_policyr )r!r;r1r#r#r$r.>s zFirewallPolicy.get_policyc Cs,dddD|_||j|j<|j|jdS)NcSsi|] }t|qSr#)r).0xr#r#r$ Csz-FirewallPolicy.add_policy..servicesports masquerade forward_ports source_ports icmp_blocksrules protocolsicmp_block_inversionr4r7) rBrCrDrErFrGrHrIrJr4r7)r<r namecopy_permanent_to_runtime)r!objr#r#r$ add_policyBs  zFirewallPolicy.add_policycCs0|j|}|jr|j||jj|j|=dS)N)r appliedunapply_policy_settingsr<r()r!r;rMr#r#r$ remove_policyNs    zFirewallPolicy.remove_policycCs|j|}|jrdSx|jD]}|j||ddqWx|jD]}|j||ddqr rOr*r/%_get_table_chains_for_policy_dispatch#_get_table_chains_for_zone_dispatchgen_chain_rulesr8_ingress_egress_zones _icmp_block _forward_port_service_port _protocol _source_port _masquerade_FirewallPolicy__ruler rr[execute) r!enabler;rb_policyrM transactiontablechainr<keyr`r#r#r$_policy_settingssj                zFirewallPolicy._policy_settingscCs|jd||ddS)NT)rb)r)r!r;rbr#r#r$rcsz$FirewallPolicy.apply_policy_settingscCs|jd||ddS)NF)rb)r)r!r;rbr#r#r$rPsz&FirewallPolicy.unapply_policy_settingsc Csr|j|j}|j||j||j||j||j||j||j||j ||j ||j |d }|j j ||S)zH :return: exported config updated with runtime settings ) rBrCrGrDrE rich_rulesrIrFr4r7)r.Zexport_config_dict list_services list_portslist_icmp_blocksquery_masqueradelist_forward_ports list_ruleslist_protocolslist_source_portslist_ingress_zoneslist_egress_zonesrZ'combine_runtime_with_permanent_settings)r!r;Z permanentZruntimer#r#r$get_config_with_settings_dictsz,FirewallPolicy.get_config_with_settings_dictc sddlmd fdd }fdd}jjfjjfjjfjj fj j f||fj j fjjfjjfjjfd }j|}jj||\}} xt| D]l} t| | trxV| | D]8} t| tr|| d|f| q|| d|| qWq|| d|qWx|D]} t|| trxn|| D]J} t| trv|| d|f| d|d n|| d|| d|d qFWn|| d|d|d q(WdS) Nr)r csj||dd|ddS)N)rkr)rgrf)r^)r;rkrgrf)r r!r#r$add_rule_wrapperszFFirewallPolicy.set_config_with_settings_dict..add_rule_wrappercsj||ddS)N)rk) remove_rule)r;rk)r r!r#r$remove_rule_wrapperszIFirewallPolicy.set_config_with_settings_dict..remove_rule_wrapper) rBrCrGrDrErrIrFr4r7rj)rgrf)rN)firewall.core.richr rWremove_servicerX remove_portrUremove_icmp_blockr_remove_masqueraderVremove_forward_portr\remove_protocolr]remove_source_portrSremove_ingress_zonerTremove_egress_zonerrZget_added_and_removed_settings isinstancelisttuple) r!r;r<rfrrZ setting_to_fnZ old_settingsZ add_settingsZremove_settingsr~r`r#)r r!r$set_config_with_settings_dicts:                z,FirewallPolicy.set_config_with_settings_dictcCs&|sttj|dkr"|jj|dS)Nr5r6)r5r6)rr INVALID_ZONEr check_zone)r!r:r#r#r$check_ingress_zones z!FirewallPolicy.check_ingress_zonecCs|j||S)N)r)r!r:r#r#r$Z__ingress_zone_id"s z FirewallPolicy.__ingress_zone_idrTc Cs|jj|}|jj||jj|j|}|j|} | |jdkrXttj d||fd|jdksd|jdks|d kr|jdrttj d|dkrd|jdkrttj d|dkr|j } n|} |rJ|j r|j d|| |j|| ||| j|j|| |j s:||jkrH|j|| d | j|j|dn|j d || n |j|| ||| j|j|| |dkr~| jd dS) Nr4z'%s' already in '%s'r6r5zI'ingress-zones' may only contain one of: many regular zones, ANY, or HOSTr7zF'HOST' can only appear in either ingress or egress zones, but not bothF)rbT)r6r5)rr> check_timeout check_panicr _FirewallPolicy__ingress_zone_idr<rrrZrr*rOro&_FirewallPolicy__register_ingress_zoneadd_fail(_FirewallPolicy__unregister_ingress_zoner=rcrerx) r!r;r:rgrfrbrRrz_objzone_idr{r#r#r$rS&s<         zFirewallPolicy.add_ingress_zonecCs|j|||jd|<dS)Nr4)_FirewallPolicy__gen_settingsr<)r!rrrgrfr#r#r$Z__register_ingress_zoneSsz&FirewallPolicy.__register_ingress_zonecCs|jj|}|jj|j|}|j|}||jdkrLttjd||f|dkr^|j }n|}|j rt |jddkr|j ||n|j d|||j|||j|j||dd||jkr|j d||n|j|j|||dkr|jd|S)Nr4z'%s' not in '%s'rjFT)rr>rr rr<rr NOT_ENABLEDr*rOlenrProrrrr=add_postrx)r!r;r:rbrzrrr{r#r#r$rVs,        z"FirewallPolicy.remove_ingress_zonecCs||jdkr|jd|=dS)Nr4)r<)r!rrr#r#r$Z__unregister_ingress_zoneysz(FirewallPolicy.__unregister_ingress_zonecCs|j||j|dkS)Nr4)rr8)r!r;r:r#r#r$query_ingress_zone}sz!FirewallPolicy.query_ingress_zonecCst|j|djS)Nr4)rr8r,)r!r;r#r#r$rsz!FirewallPolicy.list_ingress_zonescCs&|sttj|dkr"|jj|dS)Nr5r6)r5r6)rrrrr)r!r:r#r#r$check_egress_zones z FirewallPolicy.check_egress_zonecCs|j||S)N)r)r!r:r#r#r$Z__egress_zone_ids zFirewallPolicy.__egress_zone_idc Cs|jj|}|jj||jj|j|}|j|} | |jdkrXttj d||fd|jdksd|jdks|d kr|jdrttj d|dkrd|jdkrttj d|dkr|j } n|} |rJ|j r|j d|| |j|| ||| j|j|| |j s:||jkrH|j|| d | j|j|dn|j d || n |j|| ||| j|j|| |dkr~| jd dS) Nr7z'%s' already in '%s'r6r5zH'egress-zones' may only contain one of: many regular zones, ANY, or HOSTr4zF'HOST' can only appear in either ingress or egress zones, but not bothF)rbT)r6r5)rr>rrr _FirewallPolicy__egress_zone_idr<rrrZrr*rOro%_FirewallPolicy__register_egress_zoner'_FirewallPolicy__unregister_egress_zoner=rcrerx) r!r;r:rgrfrbrRrzrrr{r#r#r$rTs<         zFirewallPolicy.add_egress_zonecCs|j|||jd|<dS)Nr7)rr<)r!rrrgrfr#r#r$Z__register_egress_zonesz%FirewallPolicy.__register_egress_zonecCs|jj|}|jj|j|}|j|}||jdkrLttjd||f|dkr^|j }n|}|j rt |jddkr|j ||n|j d|||j|||j|j||dd||jkr|j d||n|j|j|||dkr|jd|S)Nr7z'%s' not in '%s'rjFT)rr>rr rr<rrrr*rOrrProrrrr=rrx)r!r;r:rbrzrrr{r#r#r$rs,        z!FirewallPolicy.remove_egress_zonecCs||jdkr|jd|=dS)Nr7)r<)r!rrr#r#r$Z__unregister_egress_zonesz'FirewallPolicy.__unregister_egress_zonecCs|j||j|dkS)Nr7)rr8)r!r;r:r#r#r$query_egress_zonesz FirewallPolicy.query_egress_zonecCst|j|djS)Nr7)rr8r,)r!r;r#r#r$rsz FirewallPolicy.list_egress_zonescCs |jdS)N)Zcheck)r!ruler#r#r$ check_ruleszFirewallPolicy.check_rulecCs|j|t|S)N)rstr)r!rr#r#r$Z __rule_ids zFirewallPolicy.__rule_idcCsx|sdS|jr,t|jrdSt|jrtdSnHt|dr@|jr@dSt|drt|jrt|j|j|j|j|j|jSdS)Nipv4ipv6macipset) Zaddrrrhasattrrr_check_ipset_type_for_source_check_ipset_applied _ipset_family)r!sourcer#r#r$_rule_source_ipvs     zFirewallPolicy._rule_source_ipvcCs|j||||dS)N) _rule_prepare)r!ryr;rr{r#r#r$Z__ruleszFirewallPolicy.__rulec CsL|jj|}|jj||jj|j|}|j|}||jdkrh|jrP|jn|} tt j d|| f|js|j rt |j t rd|jdkrtt jdd|jdkrtt jdx6|jdD](} | dkrq|jjj| rtt jd qW|j rt |j trd|jdkr,|j jrtt jd nb|jdr|j jsNtt jd x>|jdD]0} | dkrlqZ|jjj| rZtt jd qZW|jrt |jtrx>|jdD]0} | dkrq|jjj| rtt jd qW|dkr|j} n|} |jr|jd||| |j||||| j|j|||dkrH| jd|S)NrHz'%s' already in '%s'r5r7z.'masquerade' is invalid for egress zone 'HOST'r4z/'masquerade' is invalid for ingress zone 'HOST'r6zR'masquerade' cannot be used in a policy if an ingress zone has assigned interfaceszAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zonezS'forward-port' cannot be used in a policy if an egress zone has assigned interfaceszR'mark' action cannot be used in a policy if an egress zone has assigned interfacesT)r6r5)rr>rrr _FirewallPolicy__rule_idr<r/rrrZelementrrrr:list_interfacesr to_addressINVALID_FORWARDactionrr*rOrw_FirewallPolicy__register_ruler _FirewallPolicy__unregister_rulerx) r!r;rrgrfrbrzrrule_id_namer:r{r#r#r$r^ s`                 zFirewallPolicy.add_rulecCs|j|||jd|<dS)NrH)rr<)r!rrrgrfr#r#r$Z__register_ruleEszFirewallPolicy.__register_rulec Cs|jj|}|jj|j|}|j|}||jdkr\|jrD|jn|}ttj d||f|dkrn|j }n|}|j r|j d||||j |j|||dkr|jd|S)NrHz'%s' not in '%s'FT)rr>rr rr<r/rrrr*rOrwrrrx) r!r;rrbrzrrrr{r#r#r$rIs"      zFirewallPolicy.remove_rulecCs||jdkr|jd|=dS)NrH)r<)r!rrr#r#r$Z__unregister_ruledsz FirewallPolicy.__unregister_rulecCs|j||j|dkS)NrH)rr8)r!r;rr#r#r$ query_rulehszFirewallPolicy.query_rulecCst|j|djS)NrH)rr8r,)r!r;r#r#r$rkszFirewallPolicy.list_rulescCs|jj|dS)N)r check_service)r!servicer#r#r$rpszFirewallPolicy.check_servicecCs|j||S)N)r)r!rr#r#r$Z __service_idss zFirewallPolicy.__service_idc Cs|jj|}|jj||jj|j|}|j|}||jdkrh|jrP|jn|} tt j d|| f|dkrz|j } n|} |j r|j d||| |j||||| j|j|||dkr| jd|S)NrBz'%s' already in '%s'T)rr>rrr _FirewallPolicy__service_idr<r/rrrZr*rOrr!_FirewallPolicy__register_servicer#_FirewallPolicy__unregister_servicerx) r!r;rrgrfrbrzr service_idrr{r#r#r$rWws&       zFirewallPolicy.add_servicecCs|j|||jd|<dS)NrB)rr<)r!rrrgrfr#r#r$Z__register_servicesz!FirewallPolicy.__register_servicec Cs|jj|}|jj|j|}|j|}||jdkr\|jrD|jn|}ttj d||f|dkrn|j }n|}|j r|j d||||j |j|||dkr|jd|S)NrBz'%s' not in '%s'FT)rr>rr rr<r/rrrr*rOrrrrrx) r!r;rrbrzrrrr{r#r#r$rs"      zFirewallPolicy.remove_servicecCs||jdkr|jd|=dS)NrB)r<)r!rrr#r#r$Z__unregister_servicesz#FirewallPolicy.__unregister_servicecCs|j||j|dkS)NrB)rr8)r!r;rr#r#r$ query_serviceszFirewallPolicy.query_servicecCs|j|djS)NrB)r8r,)r!r;r#r#r$rszFirewallPolicy.list_servicesc CsTg}xJ|D]B}y|jjj|}Wn tk r@ttj|YnX|j|q W|S)N)rhelper get_helperrrINVALID_HELPERr0)r!helpers_helpersr_helperr#r#r$get_helpers_for_service_helperss z.FirewallPolicy.get_helpers_for_service_helperscCsg}x|D]}y|jjj|}Wn tk r@ttj|YnXt|jdkrt|j }y|jjj|}|j |Wqtk r|rt j d|w YqXq |j |q W|S)NrjzHelper '%s' is not available) rrrrrrrrCr moduler0rr[)r!modulesryrrr_module_short_namerr#r#r$get_helpers_for_service_moduless"   z.FirewallPolicy.get_helpers_for_service_modulescCs|jj||jj|dS)N)r check_port check_tcpudp)r!portprotocolr#r#r$rs zFirewallPolicy.check_portcCs|j||t|d|fS)N-)rr)r!rrr#r#r$Z __port_ids zFirewallPolicy.__port_idcs|jj|}|jj||jj|j|}ttfdd|jd} x@| D]8} t|| drN|j rl|j n|} t t j d|| fqNWt |dd| D\} } |dkr|j}n|}|jr x$| D]}|jd|t|d |qWx$| D]}|jd |t|d |qWx:| D]2}|j|} |j|| |||j|j|| qWx*| D]"}|j|} |j|j|| qNW|dkr|jd|S) Ncs |dkS)Nrjr#)r@)rr#r$sz)FirewallPolicy.add_port..rCrz'%s:%s' already in '%s'cSsg|] \}}|qSr#r#)r?rsrtr#r#r$ sz+FirewallPolicy.add_port..TrF)rr>rrr rfilterr<r r/rrrZr r*rOrsr_FirewallPolicy__port_id_FirewallPolicy__register_portr _FirewallPolicy__unregister_portrrx)r!r;rrrgrfrbrzrexisting_port_idsport_idr added_rangesremoved_rangesr{ranger#)rr$rXs:              zFirewallPolicy.add_portcCs|j|||jd|<dS)NrC)rr<)r!rrrgrfr#r#r$Z__register_portszFirewallPolicy.__register_portcs|jj|}|jj|j|}ttfdd|jd}xB|D]}t||drBPqBW|jrf|jn|} t t j d|| ft |dd|D\} } |dkr|j } n|} |jrx$| D]} |jd|t| d | qWx$| D]} |jd |t| d | qWx:| D]2} |j| }|j||dd| j|j||qWx*| D]"} |j| }| j|j||qDW|dkr~| jd|S) Ncs |dkS)Nrjr#)r@)rr#r$rsz,FirewallPolicy.remove_port..rCrz'%s:%s' not in '%s'cSsg|] \}}|qSr#r#)r?rsrtr#r#r$r#sz.FirewallPolicy.remove_port..TrF)rr>rr rrr<r r/rrrr r*rOrsrrrrrrrx)r!r;rrrbrzrrrrrrr{rr#)rr$rs:             zFirewallPolicy.remove_portcCs||jdkr|jd|=dS)NrC)r<)r!rrr#r#r$Z__unregister_port=sz FirewallPolicy.__unregister_portcCs6x0|j|dD]\}}t||r||krdSqWdS)NrCTF)r8r )r!r;rrrsrtr#r#r$ query_portAszFirewallPolicy.query_portcCst|j|djS)NrC)rr8r,)r!r;r#r#r$rHszFirewallPolicy.list_portscCst|sttj|dS)N)rrrZINVALID_PROTOCOL)r!rr#r#r$check_protocolMszFirewallPolicy.check_protocolcCs|j||S)N)r)r!rr#r#r$Z __protocol_idQs zFirewallPolicy.__protocol_idc Cs|jj|}|jj||jj|j|}|j|}||jdkrh|jrP|jn|} tt j d|| f|dkrz|j } n|} |j r|j d||| |j||||| j|j|||dkr| jd|S)NrIz'%s' already in '%s'T)rr>rrr _FirewallPolicy__protocol_idr<r/rrrZr*rOrt"_FirewallPolicy__register_protocolr$_FirewallPolicy__unregister_protocolrx) r!r;rrgrfrbrzr protocol_idrr{r#r#r$r\Us&       zFirewallPolicy.add_protocolcCs|j|||jd|<dS)NrI)rr<)r!rrrgrfr#r#r$Z__register_protocolrsz"FirewallPolicy.__register_protocolc Cs|jj|}|jj|j|}|j|}||jdkr\|jrD|jn|}ttj d||f|dkrn|j }n|}|j r|j d||||j |j|||dkr|jd|S)NrIz'%s' not in '%s'FT)rr>rr rr<r/rrrr*rOrtrrrx) r!r;rrbrzrrrr{r#r#r$rvs$       zFirewallPolicy.remove_protocolcCs||jdkr|jd|=dS)NrI)r<)r!rrr#r#r$Z__unregister_protocolsz$FirewallPolicy.__unregister_protocolcCs|j||j|dkS)NrI)rr8)r!r;rr#r#r$query_protocolszFirewallPolicy.query_protocolcCst|j|djS)NrI)rr8r,)r!r;r#r#r$rszFirewallPolicy.list_protocolscCs|j||t|d|fS)Nr)rr)r!rrr#r#r$Z__source_port_ids zFirewallPolicy.__source_port_idcs|jj|}|jj||jj|j|}ttfdd|jd} x@| D]8} t|| drN|j rl|j n|} t t j d|| fqNWt |dd| D\} } |dkr|j}n|}|jr x$| D]}|jd|t|d |qWx$| D]}|jd |t|d |qWx:| D]2}|j|} |j|| |||j|j|| qWx*| D]"}|j|} |j|j|| qNW|dkr|jd|S) Ncs |dkS)Nrjr#)r@)rr#r$rsz0FirewallPolicy.add_source_port..rFrz'%s:%s' already in '%s'cSsg|] \}}|qSr#r#)r?rsrtr#r#r$rsz2FirewallPolicy.add_source_port..TrF)rr>rrr rrr<r r/rrrZr r*rOrur_FirewallPolicy__source_port_id%_FirewallPolicy__register_source_portr'_FirewallPolicy__unregister_source_portrrx)r!r;rrrgrfrbrzrrrrrrr{rr#)rr$r]s:              zFirewallPolicy.add_source_portcCs|j|||jd|<dS)NrF)rr<)r!rrrgrfr#r#r$Z__register_source_portsz%FirewallPolicy.__register_source_portcs|jj|}|jj|j|}ttfdd|jd}xB|D]}t||drBPqBW|jrf|jn|} t t j d|| ft |dd|D\} } |dkr|j } n|} |jrx$| D]} |jd|t| d | qWx$| D]} |jd |t| d | qWx:| D]2} |j| }|j||dd| j|j||qWx*| D]"} |j| }| j|j||qDW|dkr~| jd|S) Ncs |dkS)Nrjr#)r@)rr#r$rsz3FirewallPolicy.remove_source_port..rFrz'%s:%s' not in '%s'cSsg|] \}}|qSr#r#)r?rsrtr#r#r$rsz5FirewallPolicy.remove_source_port..TrF)rr>rr rrr<r r/rrrr r*rOrurrrrrrrx)r!r;rrrbrzrrrrrrr{rr#)rr$rs:             z!FirewallPolicy.remove_source_portcCs||jdkr|jd|=dS)NrF)r<)r!rrr#r#r$Z__unregister_source_portsz'FirewallPolicy.__unregister_source_portcCs6x0|j|dD]\}}t||r||krdSqWdS)NrFTF)r8r )r!r;rrrsrtr#r#r$query_source_portsz FirewallPolicy.query_source_portcCst|j|djS)NrF)rr8r,)r!r;r#r#r$rsz FirewallPolicy.list_source_portscCsdS)NTr#)r!r#r#r$Z__masquerade_idszFirewallPolicy.__masquerade_idc Cs8|jj|}|jj||jj|j|}|j}||jdkrb|jrN|jn|}tt j d||jsd|jdkrtt j dd|jdkrtt j dx6|jdD](} | dkrq|jj j | rtt j d qW|dkr|j} n|} |jr|jd || |j||||| j|j|||dkr4| jd |S) NrDz"masquerade already enabled in '%s'r5r7z.'masquerade' is invalid for egress zone 'HOST'r4z/'masquerade' is invalid for ingress zone 'HOST'r6zR'masquerade' cannot be used in a policy if an ingress zone has assigned interfacesT)rr>rrr _FirewallPolicy__masquerade_idr<r/rrrZrr:rr*rOrv$_FirewallPolicy__register_masquerader&_FirewallPolicy__unregister_masqueraderx) r!r;rgrfrbrzr masquerade_idrr:r{r#r#r$r_ s:          zFirewallPolicy.add_masqueradecCs|j|||jd|<dS)NrD)rr<)r!rrrgrfr#r#r$Z__register_masquerade2sz$FirewallPolicy.__register_masqueradecCs|jj|}|jj|j|}|j}||jdkrV|jrB|jn|}ttj d||dkrh|j }n|}|j r|j d|||j |j|||dkr|jd|S)NrDzmasquerade not enabled in '%s'FT)rr>rr rr<r/rrrr*rOrvrrrx)r!r;rbrzrrrr{r#r#r$r6s"      z FirewallPolicy.remove_masqueradecCs||jdkr|jd|=dS)NrD)r<)r!rrr#r#r$Z__unregister_masqueradePsz&FirewallPolicy.__unregister_masqueradecCs|j|j|dkS)NrD)rr8)r!r;r#r#r$rTszFirewallPolicy.query_masqueradecCs^|jj||jj||r(|jj||rBt||sBttj|| rZ| rZttjddS)Nz.port-forwarding is missing to-port AND to-addr)rrrrrrZ INVALID_ADDRr)r!ipvrrtoporttoaddrr#r#r$check_forward_portYs      z!FirewallPolicy.check_forward_portcCsLtd|r|jd||||n|jd||||t|d|t|dt|fS)Nrrr)rrrr)r!rrrrr#r#r$Z__forward_port_idfs   z FirewallPolicy.__forward_port_idc CsZ|jj|} |jj||jj|j| } |j||||} | | jdkrt| jrV| jn| } tt j d||||| f| jsd| jdkr|rtt j dnR| jdr|stt j dx6| jdD](} | dkrq|jj j | rtt jdqW|dkr|j}n|}| jr"|jd | ||||||j| | |||j|j| | |dkrV|jd | S) NrEz'%s:%s:%s:%s' already in '%s'r5r7zAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zoner6zS'forward-port' cannot be used in a policy if an egress zone has assigned interfacesT)rr>rrr _FirewallPolicy__forward_port_idr<r/rrrZrr:rrr*rOrq&_FirewallPolicy__register_forward_portr(_FirewallPolicy__unregister_forward_portrx)r!r;rrrrrgrfrbrzr forward_idrr:r{r#r#r$rVnsB          zFirewallPolicy.add_forward_portcCs|j|||jd|<dS)NrE)rr<)r!rrrgrfr#r#r$Z__register_forward_portsz&FirewallPolicy.__register_forward_portc Cs|jj|}|jj|j|}|j||||} | |jdkrh|jrJ|jn|} ttj d||||| f|dkrz|j } n|} |j r|j d|| ||||| j |j|| |dkr| jd|S)NrEz'%s:%s:%s:%s' not in '%s'FT)rr>rr rr<r/rrrr*rOrqrrrx) r!r;rrrrrbrzrrrr{r#r#r$rs&     z"FirewallPolicy.remove_forward_portcCs||jdkr|jd|=dS)NrE)r<)r!rrr#r#r$Z__unregister_forward_portsz(FirewallPolicy.__unregister_forward_portcCs"|j||||}||j|dkS)NrE)rr8)r!r;rrrrrr#r#r$query_forward_portsz!FirewallPolicy.query_forward_portcCst|j|djS)NrE)rr8r,)r!r;r#r#r$rsz!FirewallPolicy.list_forward_portscCs|jj|dS)N)rZcheck_icmptype)r!icmpr#r#r$check_icmp_blockszFirewallPolicy.check_icmp_blockcCs|j||S)N)r)r!rr#r#r$Z__icmp_block_ids zFirewallPolicy.__icmp_block_idc Cs|jj|}|jj||jj|j|}|j|}||jdkrh|jrP|jn|} tt j d|| f|dkrz|j } n|} |j r|j d||| |j||||| j|j|||dkr| jd|S)NrGz'%s' already in '%s'T)rr>rrr _FirewallPolicy__icmp_block_idr<r/rrrZr*rOrp$_FirewallPolicy__register_icmp_blockr&_FirewallPolicy__unregister_icmp_blockrx) r!r;rrgrfrbrzricmp_idrr{r#r#r$rUs&       zFirewallPolicy.add_icmp_blockcCs|j|||jd|<dS)NrG)rr<)r!rr rgrfr#r#r$Z__register_icmp_blocksz$FirewallPolicy.__register_icmp_blockc Cs|jj|}|jj|j|}|j|}||jdkr\|jrD|jn|}ttj d||f|dkrn|j }n|}|j r|j d||||j |j|||dkr|jd|S)NrGz'%s' not in '%s'FT)rr>rr rr<r/rrrr*rOrprr rx) r!r;rrbrzrr rr{r#r#r$rs"      z FirewallPolicy.remove_icmp_blockcCs||jdkr|jd|=dS)NrG)r<)r!rr r#r#r$Z__unregister_icmp_block sz&FirewallPolicy.__unregister_icmp_blockcCs|j||j|dkS)NrG)rr8)r!r;rr#r#r$query_icmp_blockszFirewallPolicy.query_icmp_blockcCs|j|djS)NrG)r8r,)r!r;r#r#r$rszFirewallPolicy.list_icmp_blockscCsdS)NTr#)r!r#r#r$Z__icmp_block_inversion_idsz(FirewallPolicy.__icmp_block_inversion_idc Cs|jj|}|jj|j|}|j}||jdkrV|jrB|jn|}ttj d||dkrh|j }n|}|j rx&|j |dD]} |j d|| |qW|jd|||j||||j|j||||j rx&|j |dD]} |j d|| |qW|jd|||dkr|jd|S)NrJz,icmp-block-inversion already enabled in '%s'rGFT)rr>rr (_FirewallPolicy__icmp_block_inversion_idr<r/rrrZr*rOr8rp_icmp_block_inversion._FirewallPolicy__register_icmp_block_inversionr*_FirewallPolicy__undo_icmp_block_inversionrx) r!r;rfrbrzricmp_block_inversion_idrr{r`r#r#r$add_icmp_block_inversions6        z'FirewallPolicy.add_icmp_block_inversioncCs|jd||jd|<dS)NrrJ)rr<)r!rrrfr#r#r$Z__register_icmp_block_inversionEsz.FirewallPolicy.__register_icmp_block_inversioncCs|j}|jr6x&|j|dD]}|jd|||qW||jdkrP|jd|=|jr~x&|j|dD]}|jd|||qfW|jddS)NrGFrJT)r*rOr8rpr<rx)r!rzrrr{r`r#r#r$Z__undo_icmp_block_inversionJs z*FirewallPolicy.__undo_icmp_block_inversionc Cs|jj|}|jj|j|}|j}||jdkrV|jrB|jn|}ttj d||dkrh|j }n|}|j rx&|j |dD]}|j d|||qW|jd|||j|||j|j||d|j rx&|j |dD]}|j d|||qW|jd|||dkr|jd|S)NrJz(icmp-block-inversion not enabled in '%s'rGFT)rr>rr r r<r/rrrr*rOr8rpr0_FirewallPolicy__unregister_icmp_block_inversionrrrx) r!r;rbrzrrrr{r`r#r#r$remove_icmp_block_inversion\s6        z*FirewallPolicy.remove_icmp_block_inversioncCs||jdkr|jd|=dS)NrJ)r<)r!rrr#r#r$Z!__unregister_icmp_block_inversionsz0FirewallPolicy.__unregister_icmp_block_inversioncCs|j|j|dkS)NrJ)r r8)r!r;r#r#r$query_icmp_block_inversionsz)FirewallPolicy.query_icmp_block_inversionc Cs|jjj|}|jr*|jjj|jd}n|}|rT||jkrt||f|j|krtdSn ||jksp||f|j|krtdSx@|jjD]2}|jr||j kr|j ||||} |j || qW|j ||||fg|j |j || ||fgdS)Nr)rr;r.r/r:Z_zone_policiesrenabled_backendspolicies_supportedZget_available_tablesZbuild_policy_chain_rules add_rules_register_chainsr) r!r;creater|r}r{rMZtracking_policybackendrHr#r#r$rns$   zFirewallPolicy.gen_chain_rulescCsbx\|D]T\}}|r,|jj|gj||fq|j|j||ft|j|dkr|j|=qWdS)Nr)r setdefaultr0remover)r!r;rZtablesr|r}r#r#r$rs zFirewallPolicy._register_chainscCs$|jjj|dkrdS|jjj|S)Nzhash:mac)rrget_typeZ get_family)r!rKr#r#r$rszFirewallPolicy._ipset_familycCs|jjj|S)N)rrr)r!rKr#r#r$Z __ipset_typeszFirewallPolicy.__ipset_typecCsdj|g|jjj|S)N,)joinrrZ get_dimension)r!rKflagr#r#r$_ipset_match_flagssz!FirewallPolicy._ipset_match_flagscCs|jjj|S)N)rrZ check_applied)r!rKr#r#r$rsz#FirewallPolicy._check_ipset_appliedcCs*|j|}|tkr&ttjd||fdS)Nz.ipset '%s' with type '%s' not usable as source)_FirewallPolicy__ipset_typerrrZ INVALID_IPSET)r!rKZ_typer#r#r$rs  z+FirewallPolicy._check_ipset_type_for_sourcec st|jtkrjjj|jj}|dkr2|jjg}xR|jD]H}||krHq:j||j |t j |}||j_j |||||dq:Wg} |j r|j g} nH|jrt|jtst|jtrjjj|jjjrfdddD} j|j} | r&|j r |j | kr&ttjd| |j fn| g} | s4ddg} fdd| D} | |_x2tfdd| DD]} t|jtkrjjj|jj}g} t|jd kr|jrttjd xB| D].} | |jkr| j| r| j |j| qWn | j dx~| D]}t|jtkrj|j |}|j!|j"7}t#t|d d d }g}x|D]}|j$}t%|}|j&dd}|j ||j dkr| j|j  rqTt|j'dkr|j |n:x8|j'D].\}}| j(||||||j|}|j)| |qWqTW|j*|x4|j'D]*\}}| j+||||||}|j)| |q Wx.|j,D]$}| j-|||||}|j)| |q@Wx4|j.D]*\}}| j/||||||}|j)| |qpWqWqft|jt0kr|jj1}|jj2}j3||| j+||||d|}|j)| |qft|jt4kr<|jj5}j6|| j-|||d|}|j)| |qft|jt7kr|rzx&| D]} | j| rX|j8t9| qXW| j:|||}|j)| |qft|jt;kr4|jj1}|jj2}|jj<}|jj=}xD| D]<} | j| rj>| |||||r|r|j8t9| qW| j?|||||||}|j)| |qft|jt@kr|jj1}|jj2}j3||| j/||||d|}|j)| |nt|jtkst|jtkr>jjj|jj|j rjr|j jkrttjAd|j |jjft|jtkr |jr t|jtkr ttjd| jB|||}|j)| |n>|jdkrf| jC|||}|j)| |nttjdt|jqfWdS)N)included_servicescsg|]}|jkr|qSr#) destination)r?r)ictr#r$rsz0FirewallPolicy._rule_prepare..rrz;Source address family '%s' conflicts with rule family '%s'.csg|]}jj|r|qSr#)ris_ipv_enabled)r?r)r!r#r$rscsg|]}jj|qSr#)rget_backend_by_ipv)r?r@)r!r#r$rsrz"Destination conflict with service.cSs|jS)N)rK)r@r#r#r$rsz.FirewallPolicy._rule_prepare..)r~ conntracknatrrjz3rich rule family '%s' conflicts with icmp type '%s'z'IcmpBlock not usable with accept actionzUnknown element %s)rr)Dtyperrrr get_servicerKincludesrr0copydeepcopyrfamilyrrrconfig get_icmptyper%rrrrZ INVALID_RULEipvsr9ris_ipv_supportedrrrrrrr+rr replacerCbuild_policy_helper_ports_rulesrZ add_modulesbuild_policy_ports_rulesrIbuild_policy_protocol_rulesrFbuild_policy_source_ports_rulesrrrrrvaluerrrrbuild_policy_masquerade_rulesrZto_portrrbuild_policy_forward_port_rulesrZINVALID_ICMPTYPEbuild_policy_icmp_block_rulesZ*build_policy_rich_source_destination_rules)r!ryr;rr{r$svcincludeZ_ruler3Z source_ipvrZ destinationsrr%rrrrr nat_modulerprotorHrrrr#)r&r!r$rs                             zFirewallPolicy._rule_preparec Csb|jjj|}|j|j|}||j|j7}tt|ddd}|dkrN|g}x@|j D]6}||krdqV|j ||j ||j |||||dqVWg} xnd D]f} |jj | sq|jj| } t|jdkr| |jkr| j | |j| fq| df| kr| j | dfqWxV| D]L\} } x|D]} | j}t|}| jjdd }|j|| jd krf| j| j rfqt| jd kr|j|n:x8| jD].\}}| j||||| | j|}|j| |qWqWx2|jD](\}}| j||||| }|j| |qWx,|jD]"}| j|||| }|j| |qWx2|jD](\}}| j||||| }|j| |q,Wq WdS) NcSs|jS)N)rK)r@r#r#r$rsz)FirewallPolicy._service..)r~)r$rrrr)r*rrj)rr) rrr,rrrrr+r9r-rr0rrr'r(rr%rr r5Z add_moduler0r4rCr6rKrr7rIr8rFr9)r!ryr;rr{r$r>rr?Z backends_ipvrrr%rrrr@rrArHrr#r#r$rrsb               zFirewallPolicy._servicecCs<x6|jjD](}|jsq |j||||}|j||q WdS)N)rrrr7r)r!ryr;rrr{rrHr#r#r$rss  zFirewallPolicy._portcCs:x4|jjD]&}|jsq |j|||}|j||q WdS)N)rrrr8r)r!ryr;rr{rrHr#r#r$rts zFirewallPolicy._protocolcCs<x6|jjD](}|jsq |j||||}|j||q WdS)N)rrrr9r)r!ryr;rrr{rrHr#r#r$rus zFirewallPolicy._source_portcCs8d}|jt||jj|}|j||}|j||dS)Nr)rrrr(r;r)r!ryr;r{rrrHr#r#r$rvs    zFirewallPolicy._masqueradec CsXtd|rd}nd}|r(|r(|jt||jj|} | j||||||} |j| | dS)Nrr)rrrrr(r<r) r!ryr;r{rrrrrrrHr#r#r$rqs    zFirewallPolicy._forward_portc Cs|jjj|}xl|jjD]^}|js&qd}|jrXx&dD]}||jkr6|j|s6d}Pq6W|r^q|j|||} |j|| qWdS)NFrrT)rr) rr1r2rrr%r4r=r) r!ryr;rr{r&rZ skip_backendrrHr#r#r$rps   zFirewallPolicy._icmp_blockcCsh|j|j}|dkrdS|j| r0|dkr0dSx2|jjD]$}|jsHq<|j||}|j||q|jdD]}|jjj|drfPqfW|jd$|jd%|Sd&g}|jjs|jd'x4|jdD]}|jjj|drPqW|jd(x>|jdD]}|jjj|drPqW|jd)|jd*|SdS)+z:Create a list of (table, chain) needed for policy dispatchr6r4r5r7rrOr*rKmanglerLrPrNrMZ interfacesN)rrO)r*rK)rSrK)rLrK)rrO)rLrK)rrP)rrN)r*rK)r*rM)rSrK)rLrK)rrN)r*rK)rSrK)rLrK)r*rM)rrN)r*rM)rLrK)r*rK)rSrK)rrN)rLrK)r*rM)r*rK)rSrK)r r<rnftables_enabledr0r:r8)r!r;rMtcr:r#r#r$rlsj                 z4FirewallPolicy._get_table_chains_for_policy_dispatchcCsr|j|}d|jdkr4dg}|jjs0|jd|Sd|jdkrLdddgSd|jd krbddgStd|SdS)z8Create a list of (table, chain) needed for zone dispatchr5r7rrOrLrKr6 FORWARD_INr*rSr4 FORWARD_OUTrMzInvalid policy: %sN)rrO)rLrK)rrV)r*rK)rSrK)rrW)r*rM)r r<rrTr0r)r!r;rMrUr#r#r$rms  z2FirewallPolicy._get_table_chains_for_zone_dispatchFcCs|jjj|}|jr|j}n||}d|jdkrl|dkrBd|S|dkrRd|S|jsh|dkrhd|SnJd|jd kr|js|dkrd |Sn"d |jdkr|dkr|jrd |Sd |Sn0|dkr|rd|Sd|Sn|dkrd|Snd |jd krh|dkr*|jr d|Sd |Sn<|dkrL|rBd|Sd|Sn|dkr|jsd|SnN|js|dkrd |S|dkr|rd|Sd|Sn|dkrd|Std|||fS)Nr5r7rZIN_rLZPRE_rSr*r4ZOUT_r6ZFWDI_ZFWD_ZPOST_ZFWDO_z.Can't convert policy to chain name: %s, %s, %s)rSr*)rSrL)rSrL)rSrL)rr;r.r/r<r)r!r;r|Z policy_prefixZisSNATrMsuffixr#r#r$policy_base_chain_namesb                z%FirewallPolicy.policy_base_chain_name)N)N)N)N)rNNT)N)rNNT)N)rNN)N)rNN)N)rNN)N)rNN)N)rNN)N)rNN)N)NN)NN)NNrNN)NNN)NN)rNN)N)NN)N)N)N)NN)F)__name__ __module__ __qualname__r%r'r)r*r-r3r=r.rNrQrLrdrerr8rrcrPrrrrrSrrrrrrrrTrrrrrrrrrwr^rrrrrrrrWrrrrrrrrrrXrrrrrrrr\rrrrrrr]rrrrrrr_rrrrrrrVrrrrrrrrUr rr r rr rrrrrrrnrrr#r"rrrrrrsrtrurvrqrprrJrQrRrorlrmrYr#r#r#r$rs$  '  ?  . , # , # :     ' (   ' ( '   +     ) )  @ @    ( P r)'rhr.Zfirewall.core.loggerrZfirewall.functionsrrrrrrr r r r rr rrrrrrrrrrZfirewall.core.fw_transactionrZfirewallrZfirewall.errorsrZfirewall.fw_typesrZfirewall.core.baserobjectrr#r#r#r$s 04     PKpge[|q~q~*__pycache__/fw_config.cpython-36.opt-1.pycnu[3 g@sdgZddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddl mZmZmZddlmZmZmZddlmZmZmZdd lmZmZmZdd lmZmZm Z dd lm!Z!dd l"m#Z#Gd dde$Z%dS)FirewallConfigN)config)log)IcmpTypeicmptype_readericmptype_writer)Serviceservice_readerservice_writer)Zone zone_reader zone_writer)IPSet ipset_reader ipset_writer)Helper helper_reader helper_writer)Policy policy_reader policy_writer)errors) FirewallErrorc@s$eZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ ddZddZddZddZdd Zd!d"Zd#d$Zd%d&Zd'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd1d2Zd3d4Zd5d6Zd7d8Zd9d:Zd;d<Z d=d>Z!d?d@Z"dAdBZ#dCdDZ$dEdFZ%dGdHZ&dIdJZ'dKdLZ(dMdNZ)dOdPZ*dQdRZ+dSdTZ,dUdVZ-dWdXZ.dYdZZ/d[d\Z0d]d^Z1d_d`Z2dadbZ3dcddZ4dedfZ5dgdhZ6didjZ7dkdlZ8dmdnZ9dodpZ:dqdrZ;dsdtZdydzZ?d{d|Z@d}d~ZAddZBddZCddZDddZEddZFddZGddZHddZIddZJddZKddZLddZMddZNddZOddZPddZQddZRddZSddZTddZUddZVddZWddZXddZYddZZddZ[ddZ\ddZ]ddZ^ddZ_ddZ`ddZaddZbdd„ZcddĄZdddƄZedS)rcCs||_|jdS)N)_fw_FirewallConfig__init_vars)selffwr/usr/lib/python3.6/fw_config.py__init__(szFirewallConfig.__init__cCsHd|j|j|j|j|j|j|j|j|j|j |j |j |j |j |j|jfS)Nz>%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)) __class___ipsets _icmptypes _services_zones_helpersZpolicy_objects_builtin_ipsets_builtin_icmptypes_builtin_services_builtin_zones_builtin_helpers_builtin_policy_objects_firewalld_conf _policies_direct)rrrr__repr__,s zFirewallConfig.__repr__cCs^i|_i|_i|_i|_i|_i|_i|_i|_i|_i|_ i|_ i|_ d|_ d|_ d|_dS)N)r!r"r#r$r%_policy_objectsr&r'r(r)r*r+r,r-r.)rrrrZ __init_vars6szFirewallConfig.__init_varscCs4x,t|jjD]}|j|j|j|=qWx,t|jjD]}|j|j|j|=q>Wx,t|jjD]}|j|j|j|=qlWx,t|jjD]}|j|j|j|=qWx,t|jjD]}|j|j|j|=qWx,t|jjD]}|j|j|j|=qWx.t|j jD]}|j |j|j |=q$Wx.t|j jD]}|j |j|j |=qTWx.t|j jD]}|j |j|j |=qWx.t|j jD]}|j |j|j |=qW|j r|j j|` d|_ |jr |jj|`d|_|jr(|jj|`d|_|jdS)N)listr&keyscleanupr!r'r"r(r#r)r$r*r%r,r-r.r)rxrrrr3GsV         zFirewallConfig.cleanupcCs |jjjS)N)rpoliciesZquery_lockdown)rrrrlockdown_enabled~szFirewallConfig.lockdown_enabledcCs|jjj||S)N)rr5 access_check)rkeyvaluerrrr7szFirewallConfig.access_checkcCs ||_dS)N)r,)rconfrrrset_firewalld_confsz!FirewallConfig.set_firewalld_confcCs|jS)N)r,)rrrrget_firewalld_confsz!FirewallConfig.get_firewalld_confcCs(tjjtjs|jjn |jjdS)N)ospathexistsrZFIREWALLD_CONFr,clearread)rrrrupdate_firewalld_confs z$FirewallConfig.update_firewalld_confcCs ||_dS)N)r-)rr5rrr set_policiesszFirewallConfig.set_policiescCs|jS)N)r-)rrrr get_policiesszFirewallConfig.get_policiescCs,tjjtjs|jjjn |jjjdS)N) r=r>r?rZLOCKDOWN_WHITELISTr-Zlockdown_whitelistr3rA)rrrrupdate_lockdown_whitelistsz(FirewallConfig.update_lockdown_whitelistcCs ||_dS)N)r.)rZdirectrrr set_directszFirewallConfig.set_directcCs|jS)N)r.)rrrr get_directszFirewallConfig.get_directcCs(tjjtjs|jjn |jjdS)N)r=r>r?rZFIREWALLD_DIRECTr.r3rA)rrrr update_directs zFirewallConfig.update_directcCs$ttt|jjt|jjS)N)sortedsetr1r!r2r&)rrrr get_ipsetsszFirewallConfig.get_ipsetscCs$|jr||j|j<n ||j|j<dS)N)builtinr&namer!)robjrrr add_ipsetszFirewallConfig.add_ipsetcCs8||jkr|j|S||jkr(|j|Sttj|dS)N)r!r&rr INVALID_IPSET)rrMrrr get_ipsets     zFirewallConfig.get_ipsetcCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._ipsets[%s] != objz'%s' not a built-in ipset)rMr!rr NO_DEFAULTSr& _remove_ipset)rrNrrrload_ipset_defaultss    z"FirewallConfig.load_ipset_defaultscCs|jS)N) export_config)rrNrrrget_ipset_configszFirewallConfig.get_ipset_configcCsj|jrPtj|}|j|tj|_d|_|j|jkr:d|_|j|t||S|j|t||SdS)NF) rLcopy import_configrETC_FIREWALLD_IPSETSr>defaultrOr)rrNr:r4rrrset_ipset_configs     zFirewallConfig.set_ipset_configcCsx||jks||jkr$ttjd|t}|j||j|||_d||_ t j |_ d|_ d|_t||j||S)Nznew_ipset(): '%s'z%s.xmlFT)r!r&rr NAME_CONFLICTr check_namerXrMfilenamerrYr>rLrZrrO)rrMr:r4rrr new_ipsets     zFirewallConfig.new_ipsetcCstjj|}tjj|}tjj|s|tjkrx|jjD]D}|j|}|j |kr:|j|=|j |j krvd|j |j fSd|fSq:WnHxF|j jD]8}|j |}|j |kr|j |=|j |jkrd|fSdSqWdSt j d|yt||}Wn0tk r}zt jd||dSd}~XnX|j |j krJ|j |jkrJ|j|d|fS|tjkr|j |jkr|j|j j|_||j|j <d|fS|j |j kr|j |j =||j |j <|j |jkrd|fSd Sd S) NupdateremovezLoading ipset file '%s'z"Failed to load ipset file '%s': %snew)NN)NN)NN)NN)NN)r=r>basenamedirnamer?rrYr!r2r^rMr&rdebug1r ExceptionerrorrOrZ)rrMr^r>r4rNmsgrrrupdate_ipset_from_pathsP                z%FirewallConfig.update_ipset_from_pathcCs|j|jkrttj|j|jtjkr>ttjd|jtjfd|j|jf}yt j |d|Wn:t k r}zt j d||tj|WYdd}~XnX|j|j=dS)Nz '%s' != '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr!rrrPr>rrYINVALID_DIRECTORYshutilmoverfrrgr=ra)rrNrMrhrrrrS8s   zFirewallConfig._remove_ipsetcCs$|js|j r ttjd|jdS)Nz'%s' is built-in ipset)rLrZrrZ BUILTIN_IPSETrM)rrNrrrcheck_builtin_ipsetIsz"FirewallConfig.check_builtin_ipsetcCs|j||j|dS)N)rmrS)rrNrrr remove_ipsetNs zFirewallConfig.remove_ipsetcCs$|j||j||}|j||S)N)rm _copy_ipsetrS)rrNrMr_rrr rename_ipsetRs   zFirewallConfig.rename_ipsetcCs|j||jS)N)r_rU)rrNrMrrrroXszFirewallConfig._copy_ipsetcCs$ttt|jjt|jjS)N)rIrJr1r"r2r')rrrr get_icmptypes]szFirewallConfig.get_icmptypescCs$|jr||j|j<n ||j|j<dS)N)rLr'rMr")rrNrrr add_icmptypeaszFirewallConfig.add_icmptypecCs8||jkr|j|S||jkr(|j|Sttj|dS)N)r"r'rrINVALID_ICMPTYPE)rrMrrr get_icmptypegs     zFirewallConfig.get_icmptypecCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._icmptypes[%s] != objz'%s' not a built-in icmptype)rMr"rrrRr'_remove_icmptype)rrNrrrload_icmptype_defaultsns    z%FirewallConfig.load_icmptype_defaultscCs|jS)N)rU)rrNrrrget_icmptype_configzsz"FirewallConfig.get_icmptype_configcCsj|jrPtj|}|j|tj|_d|_|j|jkr:d|_|j|t||S|j|t||SdS)NF) rLrWrXrETC_FIREWALLD_ICMPTYPESr>rZrrr)rrNr:r4rrrset_icmptype_config}s     z"FirewallConfig.set_icmptype_configcCsx||jks||jkr$ttjd|t}|j||j|||_d||_ t j |_ d|_ d|_t||j||S)Nznew_icmptype(): '%s'z%s.xmlFT)r"r'rrr\rr]rXrMr^rrxr>rLrZrrr)rrMr:r4rrr new_icmptypes     zFirewallConfig.new_icmptypecCstjj|}tjj|}tjj|s|tjkrx|jjD]D}|j|}|j |kr:|j|=|j |j krvd|j |j fSd|fSq:WnHxF|j jD]8}|j |}|j |kr|j |=|j |jkrd|fSdSqWdSt j d|yt||}Wn0tk r}zt jd||dSd}~XnX|j |j krJ|j |jkrJ|j|d|fS|tjkr|j |jkr|j|j j|_||j|j <d|fS|j |j kr|j |j =||j |j <|j |jkrd|fSd Sd S) Nr`razLoading icmptype file '%s'z%Failed to load icmptype file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rrxr"r2r^rMr'rrerrfrgrrrZ)rrMr^r>r4rNrhrrrupdate_icmptype_from_pathsP                z(FirewallConfig.update_icmptype_from_pathcCs|j|jkrttj|j|jtjkr>ttjd|jtjfd|j|jf}yt j |d|Wn:t k r}zt j d||tj|WYdd}~XnX|j|j=dS)Nz '%s' != '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr"rrrsr>rrxrjrkrlrfrrgr=ra)rrNrMrhrrrrus  zFirewallConfig._remove_icmptypecCs$|js|j r ttjd|jdS)Nz'%s' is built-in icmp type)rLrZrrZBUILTIN_ICMPTYPErM)rrNrrrcheck_builtin_icmptypesz%FirewallConfig.check_builtin_icmptypecCs|j||j|dS)N)r|ru)rrNrrrremove_icmptypes zFirewallConfig.remove_icmptypecCs$|j||j||}|j||S)N)r|_copy_icmptyperu)rrNrMrzrrrrename_icmptypes   zFirewallConfig.rename_icmptypecCs|j||jS)N)rzrU)rrNrMrrrr~szFirewallConfig._copy_icmptypecCs$ttt|jjt|jjS)N)rIrJr1r#r2r()rrrr get_services szFirewallConfig.get_servicescCs$|jr||j|j<n ||j|j<dS)N)rLr(rMr#)rrNrrr add_serviceszFirewallConfig.add_servicecCs<||jkr|j|S||jkr(|j|Sttjd|dS)Nzget_service(): '%s')r#r(rrINVALID_SERVICE)rrMrrr get_services     zFirewallConfig.get_servicecCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._services[%s] != objz'%s' not a built-in service)rMr#rrrRr(_remove_service)rrNrrrload_service_defaultss    z$FirewallConfig.load_service_defaultscCsr|j}g}x\tdD]P}|j|d|krN|jtjt||j|dq|j||j|dqWt|S)Nr)export_config_dictrangeIMPORT_EXPORT_STRUCTUREappendrWdeepcopygetattrtuple)rrN conf_dict conf_listirrrget_service_config's"z!FirewallConfig.get_service_configcCs|jS)N)r)rrNrrrget_service_config_dict3sz&FirewallConfig.get_service_config_dictcCsi}x&t|D]\}}|||j|d<qW|jr|tj|}|j|tj|_d|_|j|jkrfd|_|j |t ||S|j|t ||SdS)NrF) enumeraterrLrWimport_config_dictrETC_FIREWALLD_SERVICESr>rZrr )rrNr:rrr9r4rrrset_service_config6s      z!FirewallConfig.set_service_configcCsj|jrPtj|}|j|tj|_d|_|j|jkr:d|_|j|t||S|j|t||SdS)NF) rLrWrrrr>rZrr )rrNr:r4rrrset_service_config_dictJs     z&FirewallConfig.set_service_config_dictcCs||jks||jkr$ttjd|i}x&t|D]\}}||tj|d<q2Wt}|j||j |||_ d||_ t j |_d|_d|_t||j||S)Nznew_service(): '%s'rz%s.xmlFT)r#r(rrr\rrrr]rrMr^rrr>rLrZr r)rrMr:rrr9r4rrr new_serviceZs"     zFirewallConfig.new_servicecCsx||jks||jkr$ttjd|t}|j||j|||_d||_ t j |_ d|_ d|_t||j||S)Nznew_service(): '%s'z%s.xmlFT)r#r(rrr\rr]rrMr^rrr>rLrZr r)rrMr:r4rrrnew_service_dictqs     zFirewallConfig.new_service_dictcCstjj|}tjj|}tjj|s|tjkrx|jjD]D}|j|}|j |kr:|j|=|j |j krvd|j |j fSd|fSq:WnHxF|j jD]8}|j |}|j |kr|j |=|j |jkrd|fSdSqWdSt j d|yt||}Wn0tk r}zt jd||dSd}~XnX|j |j krJ|j |jkrJ|j|d|fS|tjkr|j |jkr|j|j j|_||j|j <d|fS|j |j kr|j |j =||j |j <|j |jkrd|fSd Sd S) Nr`razLoading service file '%s'z$Failed to load service file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rrr#r2r^rMr(rrer rfrgrrZ)rrMr^r>r4rNrhrrrupdate_service_from_pathsP                z'FirewallConfig.update_service_from_pathcCs|j|jkrttj|j|jtjkr>ttjd|jtjfd|j|jf}yt j |d|Wn:t k r}zt j d||tj|WYdd}~XnX|j|j=dS)Nz '%s' != '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr#rrrr>rrrjrkrlrfrrgr=ra)rrNrMrhrrrrs  zFirewallConfig._remove_servicecCs$|js|j r ttjd|jdS)Nz'%s' is built-in service)rLrZrrZBUILTIN_SERVICErM)rrNrrrcheck_builtin_servicesz$FirewallConfig.check_builtin_servicecCs|j||j|dS)N)rr)rrNrrrremove_services zFirewallConfig.remove_servicecCs$|j||j||}|j||S)N)r _copy_servicer)rrNrMrrrrrename_services   zFirewallConfig.rename_servicecCs|j||jS)N)rr)rrNrMrrrrszFirewallConfig._copy_servicecCs$ttt|jjt|jjS)N)rIrJr1r$r2r))rrrr get_zonesszFirewallConfig.get_zonescCs$|jr||j|j<n ||j|j<dS)N)rLr)rMr$)rrNrrradd_zoneszFirewallConfig.add_zonecCs(||jkr|j|=||jkr$|j|=dS)N)r)r$)rrMrrr forget_zones  zFirewallConfig.forget_zonecCs<||jkr|j|S||jkr(|j|Sttjd|dS)Nzget_zone(): %s)r$r)rr INVALID_ZONE)rrMrrrget_zones     zFirewallConfig.get_zonecCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._zones[%s] != objz'%s' not a built-in zone)rMr$rrrRr) _remove_zone)rrNrrrload_zone_defaultss    z!FirewallConfig.load_zone_defaultscCsr|j}g}x\tdD]P}|j|d|krN|jtjt||j|dq|j||j|dqWt|S)Nr)rrrrrWrrr)rrNrrrrrrget_zone_configs"zFirewallConfig.get_zone_configcCs|jS)N)r)rrNrrrget_zone_config_dictsz#FirewallConfig.get_zone_config_dictcCsi}x&t|D]\}}|||j|d<qW|jrtj|}||_|j|tj|_d|_|j|jkrld|_ |j |t ||S||_|j|t ||SdS)NrF) rrrLrW fw_configrrETC_FIREWALLD_ZONESr>rZrr )rrNr:rrr9r4rrrset_zone_config s$     zFirewallConfig.set_zone_configcCsv|jrVtj|}||_|j|tj|_d|_|j|jkr@d|_|j|t ||S||_|j|t ||SdS)NF) rLrWrrrrr>rZrr )rrNr:r4rrrset_zone_config_dict6s     z#FirewallConfig.set_zone_config_dictcCs||jks||jkr$ttjd|i}x&t|D]\}}||tj|d<q2Wt}||_|j ||j |||_ d||_ t j|_d|_d|_t||j||S)Nznew_zone(): '%s'rz%s.xmlFT)r$r)rrr\rr rrr]rrMr^rrr>rLrZr r)rrMr:rrr9r4rrrnew_zoneHs"    zFirewallConfig.new_zonecCs~||jks||jkr$ttjd|t}||_|j||j|||_ d||_ t j |_ d|_d|_t||j||S)Nznew_zone(): '%s'z%s.xmlFT)r$r)rrr\r rr]rrMr^rrr>rLrZr r)rrMr:r4rrr new_zone_dict_s    zFirewallConfig.new_zone_dictcCstjj|}tjj|}tjj|s|jtjrx|jj D]D}|j|}|j |kr<|j|=|j |j krxd|j |j fSd|fSqrcrdr? startswithrrr$r2r^rMr)rrer rfrgrlenrrZ)rrMr^r>r4rNrhrrrupdate_zone_from_pathrsZ                z$FirewallConfig.update_zone_from_pathcCs|j|jkrttj|j|jjtjs@ttj d|jtjfd|j|jf}yt j |d|Wn:t k r}zt jd||tj|WYdd}~XnX|j|j=dS)Nz'%s' doesn't start with '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr$rrrr>rrrrjrkrlrfrrgr=ra)rrNrMrhrrrrs zFirewallConfig._remove_zonecCs$|js|j r ttjd|jdS)Nz'%s' is built-in zone)rLrZrrZ BUILTIN_ZONErM)rrNrrrcheck_builtin_zonesz!FirewallConfig.check_builtin_zonecCs|j||j|dS)N)rr)rrNrrr remove_zones zFirewallConfig.remove_zonec CsN|j||j}|j|y|j||}Wn|j|j|YnX|S)N)rrrrrM)rrNrMZobj_confrrrr rename_zones  zFirewallConfig.rename_zonecCs$ttt|jjt|jjS)N)rIrJr1r0r2r+)rrrrget_policy_objectssz!FirewallConfig.get_policy_objectscCs$|jr||j|j<n ||j|j<dS)N)rLr+rMr0)rrNrrradd_policy_objectsz FirewallConfig.add_policy_objectcCs<||jkr|j|S||jkr(|j|Sttjd|dS)Nzget_policy_object(): %s)r0r+rrINVALID_POLICY)rrMrrrget_policy_objects     z FirewallConfig.get_policy_objectcCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._policy_objects[%s] != objz'%s' not a built-in policy)rMr0rrrRr+_remove_policy_object)rrNrrrload_policy_object_defaultss    z*FirewallConfig.load_policy_object_defaultscCs|jS)N)r)rrNrrrget_policy_object_config_dictsz,FirewallConfig.get_policy_object_config_dictcCsv|jrVtj|}||_|j|tj|_d|_|j|jkr@d|_|j|t ||S||_|j|t ||SdS)NF) rLrWrrrETC_FIREWALLD_POLICIESr>rZrr)rrNr:r4rrrset_policy_object_config_dicts     z,FirewallConfig.set_policy_object_config_dictcCs~||jks||jkr$ttjd|t}||_|j||j|||_ d||_ t j |_ d|_d|_t||j||S)Nznew_policy_object(): '%s'z%s.xmlFT)r0r+rrr\rrr]rrMr^rrr>rLrZrr)rrMr:r4rrrnew_policy_object_dicts    z%FirewallConfig.new_policy_object_dictcCstjj|}tjj|}tjj|s|jtjrx|jj D]D}|j|}|j |kr<|j|=|j |j krxd|j |j fSd|fSqrcrdr?rrrr0r2r^rMr+rrerrfrgrrrrZ)rrMr^r>r4rNrhrrrupdate_policy_object_from_path,sZ                z-FirewallConfig.update_policy_object_from_pathcCs|j|jkrttj|j|jjtjs@ttj d|jtjfd|j|jf}yt j |d|Wn:t k r}zt jd||tj|WYdd}~XnX|j|j=dS)Nz'%s' doesn't start with '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr0rrrr>rrrrjrkrlrfrrgr=ra)rrNrMrhrrrrys z$FirewallConfig._remove_policy_objectcCs$|js|j r ttjd|jdS)Nz'%s' is built-in policy)rLrZrrZBUILTIN_POLICYrM)rrNrrrcheck_builtin_policy_objectsz*FirewallConfig.check_builtin_policy_objectcCs|j||j|dS)N)rr)rrNrrrremove_policy_objects z#FirewallConfig.remove_policy_objectcCs$|j||j||}|j||S)N)r_copy_policy_objectr)rrNrMZnew_policy_objectrrrrename_policy_objects   z#FirewallConfig.rename_policy_objectcCs|j||jS)N)rr)rrNrMrrrrsz"FirewallConfig._copy_policy_objectcCs$ttt|jjt|jjS)N)rIrJr1r%r2r*)rrrr get_helpersszFirewallConfig.get_helperscCs$|jr||j|j<n ||j|j<dS)N)rLr*rMr%)rrNrrr add_helperszFirewallConfig.add_helpercCs8||jkr|j|S||jkr(|j|Sttj|dS)N)r%r*rrINVALID_HELPER)rrMrrr get_helpers     zFirewallConfig.get_helpercCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._helpers[%s] != objz'%s' not a built-in helper)rMr%rrrRr*_remove_helper)rrNrrrload_helper_defaultss    z#FirewallConfig.load_helper_defaultscCs|jS)N)rU)rrNrrrget_helper_configsz FirewallConfig.get_helper_configcCsj|jrPtj|}|j|tj|_d|_|j|jkr:d|_|j|t||S|j|t||SdS)NF) rLrWrXrETC_FIREWALLD_HELPERSr>rZrr)rrNr:r4rrrset_helper_configs     z FirewallConfig.set_helper_configcCsx||jks||jkr$ttjd|t}|j||j|||_d||_ t j |_ d|_ d|_t||j||S)Nznew_helper(): '%s'z%s.xmlFT)r%r*rrr\rr]rXrMr^rrr>rLrZrr)rrMr:r4rrr new_helpers     zFirewallConfig.new_helpercCstjj|}tjj|}tjj|s|tjkrx|jjD]D}|j|}|j |kr:|j|=|j |j krvd|j |j fSd|fSq:WnHxF|j jD]8}|j |}|j |kr|j |=|j |jkrd|fSdSqWdSt j d|yt||}Wn0tk r}zt jd||dSd}~XnX|j |j krJ|j |jkrJ|j|d|fS|tjkr|j |jkr|j|j j|_||j|j <d|fS|j |j kr|j |j =||j |j <|j |jkrd|fSd Sd S) Nr`razLoading helper file '%s'z#Failed to load helper file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rrr%r2r^rMr*rrerrfrgrrZ)rrMr^r>r4rNrhrrrupdate_helper_from_pathsP                z&FirewallConfig.update_helper_from_pathcCs|j|jkrttj|j|jtjkr>ttjd|jtjfd|j|jf}yt j |d|Wn:t k r}zt j d||tj|WYdd}~XnX|j|j=dS)Nz '%s' != '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr%rrrr>rrrjrkrlrfrrgr=ra)rrNrMrhrrrr&s   zFirewallConfig._remove_helpercCs$|js|j r ttjd|jdS)Nz'%s' is built-in helper)rLrZrrZBUILTIN_HELPERrM)rrNrrrcheck_builtin_helper7sz#FirewallConfig.check_builtin_helpercCs|j||j|dS)N)rr)rrNrrr remove_helper<s zFirewallConfig.remove_helpercCs$|j||j||}|j||S)N)r _copy_helperr)rrNrMrrrr rename_helper@s   zFirewallConfig.rename_helpercCs|j||jS)N)rrU)rrNrMrrrrFszFirewallConfig._copy_helperN)f__name__ __module__ __qualname__rr/rr3r6r7r;r<rBrCrDrErFrGrHrKrOrQrTrVr[r_rirSrmrnrprorqrrrtrvrwryrzr{rur|r}rr~rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr's 7 E E  E  M M E)&__all__rWr=Zos.pathrkZfirewallrZfirewall.core.loggerrZfirewall.core.io.icmptyperrrZfirewall.core.io.servicerr r Zfirewall.core.io.zoner r r Zfirewall.core.io.ipsetrrrZfirewall.core.io.helperrrrZfirewall.core.io.policyrrrrZfirewall.errorsrobjectrrrrrs    PKpge[ = "__pycache__/watcher.cpython-36.pycnu[3 g @s*dgZddlmZmZGdddeZdS)Watcher)GioGLibc@sdeZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ dS)rcCs"||_||_i|_i|_g|_dS)N) _callback_timeout _monitors _timeouts_blocked)selfcallbackZtimeoutr /usr/lib/python3.6/watcher.py__init__s zWatcher.__init__cCs:tjj|}|jtjjd|j|<|j|jd|jdS)Nchanged) rFile new_for_pathZmonitor_directoryFileMonitorFlagsNONErconnect_file_changed_cb)r Z directorygfiler r r add_watch_dir"s zWatcher.add_watch_dircCs:tjj|}|jtjjd|j|<|j|jd|jdS)Nr) rrrZ monitor_filerrrrr)r filenamerr r r add_watch_file(s zWatcher.add_watch_filecCs |jjS)N)rkeys)r r r r get_watches.szWatcher.get_watchescCs ||jkS)N)r)r rr r r has_watch1szWatcher.has_watchcCs |j|=dS)N)r)r rr r r remove_watch4szWatcher.remove_watchcCs||jkr|jj|dS)N)r append)r rr r r block_source7s zWatcher.block_sourcecCs||jkr|jj|dS)N)r remove)r rr r r unblock_source;s zWatcher.unblock_sourcecCs4x.t|jjD]}tj|j||j|=qWdS)N)listrrr source_remove)r rr r r clear_timeouts?szWatcher.clear_timeoutscCs ||jkr|j||j|=dS)N)r rr)r rr r r _call_callbackDs  zWatcher._call_callbackcCs|j}||jkr8||jkr4tj|j||j|=dS|tjjksh|tjjksh|tjj ksh|tjj kr||jkrtj|j||j|=tj |j |j ||j|<dS)N)Zget_parse_namer rrr#rZFileMonitorEventZCHANGEDZCREATEDZDELETEDZATTRIBUTE_CHANGEDZtimeout_add_secondsrr%)r ZmonitorZgio_fileZgio_other_fileZeventrr r r rIs       zWatcher._file_changed_cbN)__name__ __module__ __qualname__rrrrrrrr!r$r%rr r r r rsN)__all__Z gi.repositoryrrobjectrr r r r sPKpge[8&)__pycache__/nftables.cpython-36.opt-1.pycnu[3 g%@slddlmZddlZddlZddlZddlmZddlmZm Z m Z m Z m Z ddl mZmZmZmZmZmZmZddlmZmZmZmZmZmZmZddlmZdZed d Z d Z!d Z"id ddCe"fiddDe"fdde"fddde"fdde"fdde"fdde"fddZ#dEddZ$e$ddde$dde$dde$dde$ddde$ddd e$ddd e$dd!d"e$ddd#e$ddd"e$dd$d"e$ddd%e$dd!de$ddd&e$ddde$dd$e$ddd'e$ddd(e$ddd)e$dd!e$dd$d"e$dd*e$dd+e$dd,e$ddd-e$dd.e$dd/e$dd0e$dd!d'e$ddd1e$dd!d)e$ddd2e$dd.d"e$dd.dd3"e$d4dd'e$d4d$de$d4dd)e$d4dd"e$d4de$d4de$d4de$d4dd-e$d4d5e$d4d6e$d4d7e$d4d8e$d4d9e$d4d:e$d4dde$d4d;e$d4d$e$d4dde$d4d<e$d4dd&e$d4d=e$d4d>e$d4d.e$d4d.d"e$d4d.de$d4d$d"e$d4d$d)d?d@Z%GdAdBdBe&Z'dS)F)absolute_importN)log) check_mac getPortRange normalizeIP6check_single_address check_address) FirewallError UNKNOWN_ERROR INVALID_RULEINVALID_ICMPTYPE INVALID_TYPE INVALID_ENTRY INVALID_PORT) Rich_Accept Rich_Reject Rich_Drop Rich_MarkRich_MasqueradeRich_ForwardPortRich_IcmpBlock)NftablesZ firewalld_Z policy_dropZpolicy_ PREROUTING preroutingdZ postrouting)r POSTROUTINGinputforwardoutput)rINPUTFORWARDOUTPUT)rawmanglenatfiltercCsHdd|ddid|dig}|dk rD|jdd|ddid|di|S)Nmatchpayloadtype)protocolfieldz==)leftoprightcode)append)r,r+r1 fragmentsr4/usr/lib/python3.6/nftables.py_icmp_types_fragmentsSs  r6icmpzdestination-unreachable z echo-replyz echo-requestredirectzparameter-problemzrouter-advertisementzrouter-solicitationz source-quenchz time-exceededztimestamp-replyztimestamp-request )"zcommunication-prohibitedzdestination-unreachablez echo-replyz echo-requestzfragmentation-neededzhost-precedence-violationzhost-prohibitedz host-redirectz host-unknownzhost-unreachablez ip-header-badznetwork-prohibitedznetwork-redirectznetwork-unknownznetwork-unreachablezparameter-problemzport-unreachablezprecedence-cutoffzprotocol-unreachabler;zrequired-option-missingzrouter-advertisementzrouter-solicitationz source-quenchzsource-route-failedz time-exceededztimestamp-replyztimestamp-requestztos-host-redirectztos-host-unreachableztos-network-redirectztos-network-unreachablezttl-zero-during-reassemblyzttl-zero-during-transiticmpv6zmld-listener-donezmld-listener-queryzmld-listener-reportzmld2-listener-reportznd-neighbor-advertznd-neighbor-solicitzpacket-too-bigz nd-redirectznd-router-advertznd-router-solicit)zaddress-unreachablez bad-headerz beyond-scopezcommunication-prohibitedzdestination-unreachablez echo-replyz echo-requestz failed-policyzmld-listener-donezmld-listener-queryzmld-listener-reportzmld2-listener-reportzneighbour-advertisementzneighbour-solicitationzno-routezpacket-too-bigzparameter-problemzport-unreachabler;z reject-routezrouter-advertisementzrouter-solicitationz time-exceededzttl-zero-during-reassemblyzttl-zero-during-transitzunknown-header-typezunknown-option)ipv4ipv6c@s`eZdZdZdZddZddZddZdd Zd d Z d d Z ddZ dddZ ddZ ddZddZddZdddZddZdd d!Zd"d#Zdd%d&Zdd(d)Zdd*d+Zdd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z!d@dAZ"dBdCZ#dDdEZ$dFdGZ%dHdIZ&ddJdKZ'dLdMZ(dNdOZ)dPdQZ*dRdSZ+ddTdUZ,ddVdWZ-ddXdYZ.dZd[Z/dd\d]Z0dd^d_Z1dd`daZ2ddbdcZ3ddddeZ4dfdgZ5ddhdiZ6djdkZ7ddldmZ8dndoZ9dpdqZ:drdsZ;dtduZdzd{Z?dd|d}Z@d~dZAddZBddZCddZDddZEddZFddZGdddZHdS)nftablesTcCsb||_d|_g|_i|_i|_i|_i|_i|_gggd|_t |_ |j j d|j j ddS)NT)inetipip6) _fwZrestore_command_existsZavailable_tablesrule_to_handlerule_ref_countrich_rule_priority_countspolicy_priority_countszone_source_index_cachecreated_tablesrrIZset_echo_outputZset_handle_output)selffwr4r4r5__init__s znftables.__init__cCsxdD]}||krPqWd||dkr`||ddd||dddf}||dd=n(d||dkrd}||dd=ndS||dd }|r|dkr||kr|||kr||j|n|dkr||krg||<|r(|||kr||j|||jd d d ||j|}n|jjr8d }n t||}||}||=|d krf||d<n |d8}||d<||ddd<dS)Naddinsertdeletez%%ZONE_SOURCE%%rulezoneaddressz%%ZONE_INTERFACE%%familycSs|dS)Nrr4)xr4r4r5sz3nftables._run_replace_zone_source..)keyrr<index)rWrXrY)remover2sortrarM_allow_zone_driftinglen)rTrZrRverbZ zone_sourcer]ra _verb_snippetr4r4r5_run_replace_zone_sourcesD        z!nftables._run_replace_zone_sourcecCsBd|krdtj|diSd|kr4dtj|diSttddS)NrXrYrWzFailed to reverse rule)copydeepcopyr r )rTdictr4r4r5 reverse_rules znftables.reverse_rulec Csxd D]}||krPqW|||dkr||d|}||d|=t|tkr^ttd||dd||ddf}|dkr||ks|||ks|||dkrttd |||d 8<n||kri||<|||krd|||<d}xVt||jD]B}||kr"|dkr"P||||7}||kr|dkrPqW|||d 7<||} ||=|dkr| |d<n |d 8}| |d<||ddd <dS) NrWrXrYrZz%priority must be followed by a numberr]chainrz*nonexistent or underflow of priority countr<ra)rWrXrY)r+intr r r sortedkeys) rTrZZpriority_countstokenrfpriorityrmraprgr4r4r5_set_rule_replace_prioritysD          z#nftables._set_rule_replace_prioritycCsfx`d D]X}||krd||krtj||d}xd D]}||kr6||=q6Wtj|dd }|SqWdS) NrWrXrYrZrahandlepositionT)Z sort_keys)rWrXrY)rarurv)rirjjsondumps)rTrZrfrule_keyZnon_keyr4r4r5 _get_rule_keys   znftables._get_rule_keycCsLdddddg}dddg}g}g}tj|j}tj|j}tj|j} |jj} x|D]} t| tkrvtt d| x|D]} | | kr|Pq|W| | krtt d| |j | } | | krDt j d|j| | | | dkr| | d 7<qVnX| | d kr | | d 8<qVn6| | d kr,| | d 8<ntt d | | | fn| r\| dkr\d | | <|j| tj| }| rttd|| d d || d d <|j||d |j||d|j|| | dkrdd |dd d|dd d|dd d|j| dii}|j|qVWdddd iig|i}t jdkrVt jd|jtj||jj|\}}}|dkrtdd|tj|f||_||_| |_| |_d}x|D]} |d 7}|j | } | s̐qd| kr|j| =|j| =qx"|D]} | |d|krPqW| |d|kr$q|d|| d d|j| <qWdS)NrWrXrYflushreplacez#rule must be a dictionary, rule: %szno valid verb found, rule: %sz%s: prev rule ref cnt %d, %sr<z)rule ref count bug: rule_key '%s', cnt %drZexprz%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%r]tablerm)r]r~rmrurIZmetainfoZjson_schema_versionr@z.%s: calling python-nftables with JSON blob: %srz'%s' failed: %s JSON blob: %szpython-nftablesru)rirjrPrQrRrOr+rkr r r rzrZdebug2 __class__r2listr(rtrhrNZgetDebugLogLevelZdebug3rwrxrIZjson_cmd ValueError)rTrules log_deniedZ _valid_verbsZ_valid_add_verbsZ_deduplicated_rulesZ_executed_rulesrPrQrRrOrZrfryZ_ruleZ json_blobZrcr!errorrar4r4r5 set_rules+s             &         znftables.set_rulescCs|j|g|dS)N)r)rTrZrr4r4r5set_rulesznftables.set_ruleNcCs|r |gStjS)N)IPTABLES_TO_NFT_HOOKrp)rTr~r4r4r5get_available_tablessznftables.get_available_tablescCsFg}xdD]6}|jdddtd d |fd |dtd ddiiq:W|dkr|jdddtdii|jdjtx>dD]6}|jdddtd d |fd |dtd ddiiqW||jd7}nz|dkrfx4|jdD]&}|j|}||jkr |j|q W||jt7}t|jdkrp|jdjtn t t d|S)NZPANICrWr~rJ)r]rrr!rmz%s_%sr%r(i,r<drop)r]r~rr+rpriopolicyDROPrr rTACCEPTFznot implemented)rr!i)rr r!) r2rrSNFT_HOOK_OFFSETrrzrNrrbr r )rTrrrrZrr4r4r5build_set_policy_rulessH               znftables.build_set_policy_rulescCs<t}x,|r|gntjD]}|jt|jqWt|S)N)rICMP_TYPES_FRAGMENTSrpupdater)rTipvZ supportedZ_ipvr4r4r5supported_icmp_typessznftables.supported_icmp_typescCs>g}x4dD],}|jdd|tdii|j|jtq W|S)NrJrKrLrWr~)r]r)rJrKrL)r2rrS)rTZdefault_tablesr]r4r4r5build_default_tabless   znftables.build_default_tablesoffcCsg}xtdjD]}|jdddtd|ddtd|dtd|d d iixz|jjrld d d dgnd d dgD]X}|jdddtd||fdii|jdddtd|ddd||fiigdiiqvWqWxd?D]}xtdjD]}|jdd|td|ddtd|dtd|d d iix~|jjrJd d d dgnd d dgD]Z}|jdd|td||fdii|jdd|td|ddd||fiigdiiqTWqWqWxVtdjD]F}|jdddtd|ddtd|dtd|d d iiqW|jdddtddddddiid d!d"d#gid$id%digdii|jdddtdddddd&iid d'd$id%digdii|jdddtdddd(dd)iid*d+d$id%digdiix~|jjrd d d dgnd d dgD]Z}|jdddtd,d|fdii|jdddtddddd,d|fiigdiiqW|d-kr|jdddtddddddiid d!d.gid$i|j|d/d0d1iigdii|jdddtddddddiid d!d.gid$id2digdii|d-kr$|jdddtdd|j|d/d0d3iigdii|jdddtddd4d5d6d7igdii|jdddtdd8ddddiid d!d"d#gid$id%digdii|jdddtdd8dddd&iid d'd$id%digdii|jdddtdd8dd(dd)iid*d+d$id%digdiixbd@D]Z}|jdddtd,d8|fdii|jdddtdd8ddd,d8|fiigdiiqWxdAD]}xz|jjrd d gnd gD]^}|jdddtd;d8||fdii|jdddtdd8ddd;d8||fiigdiiqWqvWxbdBD]Z}|jdddtd,d8|fdii|jdddtdd8ddd,d8|fiigdiiqW|d-kr|jdddtdd8ddddiid d!d.gid$i|j|d/d0d1iigdii|jdddtdd8ddddiid d!d.gid$id2digdii|d-kr6|jdddtdd8|j|d/d0d3iigdii|jdddtdd8d4d5d6d7igdii|jdddtdd<ddddiid d!d"d#gid$id%digdii|jdddtd=dd(dd>iid*d+d$id%digdiixbdCD]Z}|jdddtd,d<|fdii|jdddtdd<ddd,d<|fiigdiiqWxbdDD]Z}|jdddtd,d<|fdii|jdddtdd<ddd,d<|fiigdiiqHW|S)ENr&rWrmrJz mangle_%sr(z%srr<)r]r~rr+rr POLICIES_preZ ZONES_SOURCEZZONES POLICIES_postz mangle_%s_%s)r]r~rrZjumptarget)r]r~rmr}rKrLr'znat_%sz nat_%s_%sz filter_%sr"r)rr`rrrrr)r.r/r0rZstatusdnatmetaiifnamez==loz filter_%s_%srZinvalidrprefixzSTATE_INVALID_DROP: rzFINAL_REJECT: rejecticmpxzadmin-prohibited)r+r}r#INOUTzfilter_%s_%s_%sr$ filter_OUTPUToifname)rKrL)r)rr)r)r)r)rrpr2rrMrd_pkttype_match_fragment)rTrZ default_rulesrmZdispatch_suffixr] directionr4r4r5build_default_rules s $  (  &  .        &  &                 &   .   &               &   &znftables.build_default_rulescCs4|dkrdddgS|dkr dgS|dkr0ddgSgS) Nr(r" FORWARD_IN FORWARD_OUTr&rr'rr4)rTr~r4r4r5get_zone_table_chainss znftables.get_zone_table_chainsrJc  sdkr\dkr\g} | jj|||||dd | jj|||||dd | Sjjj|jdkrxdnddkrd krd nd } jjj|t| g} g} |r| jd d ddiiddt |idi|r| jd d ddiiddt |ididdd}|rlxT|D]L}dkrTjj j |}||krT||krTq| jj d|qW|rxT|D]L}dkrjj j |}||kr||krqx| jj d|qxWfdd}g} | rHx| D]P}| rxB| D]}| j|||qWn"dkr0|r0n| j||dqWn\dkrZ|rZnJ| rxB| D]}| j|d|qfWn"dkr|rn| j|dd| S)Nr'rJrK)r]rLrprepostrTFr)rr`rz==r)r.r/r0r)rGrHsaddrdaddrcsg}|r|j||r |j||jdddfiitdf|d}|jjrrdd|iiSdd|iiSdS) Nrrz%s_%sz%s_%s_POLICIES_%s)r]r~rmr}rWrZrY)r2rr_policy_priority_fragment)ingress_fragmentegress_fragmentexpr_fragmentsrZ)_policyrm chain_suffixrr]p_objrTr~r4r5_generate_policy_dispatch_rules    zRnftables.build_policy_ingress_egress_rules.._generate_policy_dispatch_rule) extend!build_policy_ingress_egress_rulesrMrZ get_policyrrpolicy_base_chain_namePOLICY_CHAIN_PREFIXr2rr[Z check_source_rule_addr_fragment)rTrrr~rmZingress_interfacesZegress_interfacesZingress_sourcesZegress_sourcesr]risSNATZingress_fragmentsZegress_fragmentsZ ipv_to_familysrcrdstrrrr4)rrmrrr]rrTr~r5rsv          z*nftables.build_policy_ingress_egress_rulesFc  Cs|dkrT|dkrTg} | j|j|||||||d| j|j|||||||d| S|dkrh|dkrhdnd} |jjj||t| d} d d d d d d d |} |t|d d kr|dt|d d}d} |dkr| dd|| fiig}n,ddd| iid|di| dd|| fiig}|rL| rLd}|td||f|d}|j|j nP|rnd}|td||f|d}n.d}|td||f|d}|s|j|j |d|iigS)Nr'rJrKrLrTF)rrr)rrr"rrr$r<+*gotorz%s_%sr)rr`z==)r.r/r0rXz %s_%s_ZONES)r]r~rmr}rWrYrZ) r!build_zone_source_interface_rulesrMrrrrerr_zone_interface_fragment)rTrr[r interfacer~rmr2r]rrroptactionrrfrZr4r4r5rQs\     z*nftables.build_zone_source_interface_rulesc Csn|dkr|dkrg}|jdr6|j|tdd} nd} td|sTt|sT| dkrp|j|j||||||dtd|st|s| dkr|j|j||||||d|S|dkr|dkrd nd } |jjj ||t | d } d d d|} ddddddd|} |jj rd||f}n d||f}d}|t ||j | ||dd|| fiigd}|j|j||| d|iigS)Nr'rJzipset:rGrKrHrLrTF)rrXrY)TFrr)rrr"rrr$z%s_%s_ZONES_SOURCEz %s_%s_ZONESrrz%s_%s)r]r~rmr}rZ) startswith_set_get_familyrerrrbuild_zone_source_address_rulesrMrrrrdrrr_zone_source_fragment)rTrr[rr\r~rmr]rZ ipset_familyrrrrZzone_dispatch_chainrrZr4r4r5rsB    z(nftables.build_zone_source_address_rulesc Cs|dkrH|dkrHg}|j|j||||d|j|j||||d|Sddd|}|dkrj|dkrjd nd }|jjj||t|d } g}|j|d |td || fdiix0d!D](} |j|d |td|| | fdiiqWxDd"D]<} |j|d|td || fddd|| | fiigdiiqW|jjj|j } |jj dkr|dkr| d#kr| } | dkrhd} |j|d|td || f|j |jj ddd| | fiigdii|dkr| d$kr| d%kr|j } n | j di} |j|d|td || f| gdii|s|j|S)&Nr'rJrKrLrWrY)TFrTF)rrmz%s_%s)r]r~rrrdenyallowrz%s_%s_%srZrr)r]r~rmr}rr(REJECT %%REJECT%%rrz"filter_%s_%s: "r)rrrrr)rrrrr)rrr)rrrr)rr)rbuild_policy_chain_rulesrMrrrr2rZ _policiesrget_log_deniedr_reject_fragmentlowerreverse)rTrrr~rmr]rrrrrrZ log_suffixtarget_fragmentr4r4r5rsZ      &             z!nftables.build_policy_chain_rulescCs<|dkr iS|d kr,ddddiid |d iSttd |dS) Nallunicast broadcast multicastr)rr`pkttypez==)r.r/r0zInvalid pkttype "%s")rrr)r r )rTrr4r4r5rs  z nftables._pkttype_match_fragmentcCsddddiddddiddddiddddiddddiddddiddddiddddiddddiddddiddd diddd diddd diddd didd d diddd diddd diddd diddd diddddiddddidddiidddiid}||S)Nrr7zhost-prohibited)r+r}znet-prohibitedzadmin-prohibitedrFznet-unreachablezhost-unreachablezport-unreachablerzprot-unreachablezaddr-unreachablezno-router+z tcp reset)zicmp-host-prohibitedz host-prohibzicmp-net-prohibitedz net-prohibzicmp-admin-prohibitedz admin-prohibzicmp6-adm-prohibitedzadm-prohibitedzicmp-net-unreachablez net-unreachzicmp-host-unreachablez host-unreachzicmp-port-unreachablezicmp6-port-unreachablez port-unreachzicmp-proto-unreachablez proto-unreachzicmp6-addr-unreachablez addr-unreachzicmp6-no-routezno-routez tcp-resetztcp-rstr4)rTZ reject_typeZfragsr4r4r5_reject_types_fragments0                      znftables._reject_types_fragmentcCsddddiS)Nrrzadmin-prohibited)r+r}r4)rTr4r4r5rsznftables._reject_fragmentcCs ddddiiddddgid iS) Nr)rr`l4protoz==rr7rF)r.r/r0r4)rTr4r4r5_icmp_match_fragment"s znftables._icmp_match_fragmentcCsP|siSddddd}|j\}}|||d}|j}|dk rH||d<d|iS) NsecondZminuteZhourZday)smhd)rateZperburstlimit)Z value_parseZ burst_parse)rTrZ rich_to_nftrZdurationrrr4r4r5_rich_rule_limit_fragment's  z"nftables._rich_rule_limit_fragmentcCst|jtttgkrn<|jrHt|jtttt gkrRt t dt|jn t t d|j dkrt|jttgkst|jtt gkrdSt|jtgkst|jttgkrdSn|j dkrdSdSdS)NzUnknown action %szNo rule action specified.rrrrr) r+elementrrrrrrrrr r rr)rT rich_ruler4r4r5_rich_rule_chain_suffix?s    z nftables._rich_rule_chain_suffixcCs>|j r|j rttd|jdkr(dS|jdkr6dSdSdS)NzNot log or auditrrrr)rauditr r rr)rTrr4r4r5 _rich_rule_chain_suffix_from_logUs   z)nftables._rich_rule_chain_suffix_from_logcCsddiS)Nz%%ZONE_INTERFACE%%r4)rTr4r4r5r`sz!nftables._zone_interface_fragmentcCsNtd|rt|}n,td|r@|jd}t|dd|d}d||diS)NrH/rr<z%%ZONE_SOURCE%%)r[r\)rrrsplit)rTr[r\Z addr_splitr4r4r5rcs     znftables._zone_source_fragmentcCs d|jiS)Nz%%POLICY_PRIORITY%%)rr)rTrr4r4r5rksz"nftables._policy_priority_fragmentcCs| s|jdkriSd|jiS)Nrz%%RICH_RULE_PRIORITY%%)rr)rTrr4r4r5_rich_rule_priority_fragmentnsz%nftables._rich_rule_priority_fragmentc Cs|js iS|jjj||t}ddd|}|j|}i} |jjrPd|jj| d<|jjr|d|jjkrhdn|jj} d| | d<d td |||f||j |jj d | igd } | j |j ||d | iiS)NrWrY)TFz%srZwarningwarnlevelrJz%s_%s_%sr)r]r~rmr}rZ) rrMrrrrrrrrrrr) rTrrrr~rrrrZ log_optionsrrZr4r4r5_rich_rule_logss&    znftables._rich_rule_logc Cs|js iS|jjj||t}ddd|}|j|}dtd|||f||j|jjdddiigd } | j |j ||d | iiS) NrWrY)TFrJz%s_%s_%srrr)r]r~rmr}rZ) rrMrrrrrrrrr) rTrrrr~rrrrrZr4r4r5_rich_rule_audits   znftables._rich_rule_auditc Cs|js iS|jjj||t}ddd|}|j|}d|||f} t|jtkr\ddi} nt|jtkr|jjr|j |jj} nddi} nt|jt krddi} nt|jt krHd}|jjj||t}d|||f} |jj j d } t| d kr,dd d d iiddd d d ii| d gi| dgidi} ndd d d ii| ddi} nttdt|jdt| ||j|jj| gd} | j|j||d| iiS)NrWrY)TFz%s_%s_%srrrr&rr<rr`mark^&r)r`valuezUnknown action %srJ)r]r~rmr}rZ)rrMrrrrr+rrrrrrrrer r rrrrr) rTrrrr~rrrrrmZ rule_actionrrZr4r4r5_rich_rule_actionsB     , znftables._rich_rule_actioncCs|jdr0|j|tddd|kr(dnd|St|r>d}ntd|rNd}nvtd|rd}tj|dd}d |jj |j d i}nDtd |rd }t |}n,d }|j d }d t |dt |dd i}dd||di|rdnd|diSdS)Nzipset:rTFetherrGrK)strictr)addrrerHrLrrr<r)r*)r,r-z!=z==)r.r/r0)r_set_match_fragmentrerrr ipaddressZ IPv4NetworkZnetwork_addressZ compressedZ prefixlenrrrn)rTZ addr_fieldr\invertr]Znormalized_addressZaddr_lenr4r4r5rs( &      znftables._rule_addr_fragmentcCs6|siS|d krttd|ddddiid|d iS) NrGrHzInvalid familyr)rr`nfprotoz==)r.r/r0)rGrH)r r )rTZ rich_familyr4r4r5_rich_rule_family_fragments  z#nftables._rich_rule_family_fragmentcCs8|siS|jr|j}n|jr&d|j}|jd||jdS)Nzipset:r)r)r ipsetrr)rTZ rich_destr\r4r4r5_rich_rule_destination_fragments z(nftables._rich_rule_destination_fragmentcCsZ|siS|jr|j}n2t|dr.|jr.|j}nt|drH|jrHd|j}|jd||jdS)Nmacrzipset:r)r)r hasattrrrrr)rTZ rich_sourcer\r4r4r5_rich_rule_source_fragments z#nftables._rich_rule_source_fragmentcCsPt|}t|tr$|dkr$ttn(t|dkr8|dSd|d|dgiSdS)Nrr<range)r isinstancernr rre)rTportrr4r4r5_port_fragments   znftables._port_fragmentc Csbddd|}d}|jjj||t} g} |r>| j|j|j|rT| j|jd||r|| j|j|j | j|j |j | jdd|dd id |j |d i| st |jtkr| jdd d diiddddgid ig} |r0| j|j||||| | j|j||||| | j|j||||| n.| j|ddtd|| f| ddigdii| S)NrWrY)TFr(rr)r*dport)r,r-z==)r.r/r0rr`rrrnew untrackedrZrJz %s_%s_allowr)r]r~rmr})rMrrrr2rr]rr destinationrsourcerr+rrrrrr) rTrrprotorrrrr~rrrr4r4r5build_policy_ports_ruless:   z!nftables.build_policy_ports_rulesc CsZddd|}d}|jjj||t}g} |r>| j|j|j|rT| j|jd||r|| j|j|j | j|j |j | jdddd iid |d i| st |j tkr| jdd dd iiddddgid ig} |r(| j|j||||| | j|j||||| | j|j||||| n.| j|ddtd||f| ddigdii| S)NrWrY)TFr(rr)rr`rz==)r.r/r0rrrrrrrZrJz %s_%s_allowr)r]r~rmr})rMrrrr2rr]rrrrrr+rrrrrr) rTrrr,rrrr~rrrr4r4r5build_policy_protocol_rules2s8   z$nftables.build_policy_protocol_rulesc Csbddd|}d}|jjj||t} g} |r>| j|j|j|rT| j|jd||r|| j|j|j | j|j |j | jdd|dd id |j |d i| st |jtkr| jdd d diiddddgid ig} |r0| j|j||||| | j|j||||| | j|j||||| n.| j|ddtd|| f| ddigdii| S)NrWrY)TFr(rr)r*sport)r,r-z==)r.r/r0rr`rrrrrrZrJz %s_%s_allowr)r]r~rmr})rMrrrr2rr]rrrrrrr+rrrrrr) rTrrrrrrrr~rrrr4r4r5build_policy_source_ports_rulesUs:   z(nftables.build_policy_source_ports_rulesc Csd}|jjj||t} ddd|} g} |rR| jdddtd||f||diig} |rl| j|jd || jd d |d d id|j|di| jdd||fi| j| ddtd| | dii| S)Nr(rWrY)TFz ct helperrJz helper-%s-%s)r]r~rr+r,rr)r*r)r,r-z==)r.r/r0rZzfilter_%s_allow)r]r~rmr})rMrrrr2rrr) rTrrrrrZ helper_nameZmodule_short_namer~rrrrr4r4r5build_policy_helper_ports_ruleszs.    z(nftables.build_policy_helper_ports_rulesc Csddd|}|jjj||t}g} |rv|t|ddkrT|dt|dd}ddd d iid |d id dig} n|jd|d dig} dtd|| d} | j|d| ii| S)NrWrY)TFr<rrr)rr`rz==)r.r/r0rrrJzfilter_%s_allow)r]r~rmr}rZ)rMrrrrerrr2) rTrr[rr~rrrrrr}rZr4r4r5build_zone_forward_ruless"  z!nftables.build_zone_forward_rulesc Csd}|jjj||tdd}ddd|}g}|r`|j|j|j|j|j|j|j |} nd} |t d|| f|d d d d iid ddiddigd} | j |j ||d| iigS)Nr'T)rrWrY)TFrz nat_%s_%sr)rr`rz!=r)r.r/r0Z masquerade)r]r~rmr}rZ) rMrrrr2rrrrrrrr) rTrrr]rr~rrrrrZr4r4r5"_build_policy_masquerade_nat_ruless&   z+nftables._build_policy_masquerade_nat_rulesc Cs^g}|rD|jr|jdks,|jrDtd|jjrD|j|j||d|nV|r|jrX|jdksl|jrtd|jjr|j|j||d|n|j|j||d|d}|jjj||t }ddd|}g}|r|j |j |j |j |j |j|j|} nd } d td || f|d d ddiiddddgididdigd} | j|j||j |d| ii|S)NrHrLrGrKr(rWrY)TFrrJz filter_%s_%sr)rr`rrrrr)r.r/r0r)r]r~rmr}rZ)r]rrr rr&rMrrrr2rrrrrrr) rTrrrrr~rrrrrZr4r4r5build_policy_masquerade_ruless8   z&nftables.build_policy_masquerade_rulesc Cs$d} |jjj|| t} ddd|} g} |r\| j|j|j| j|j|j|j |} nd} | jdd|dd id |j |d i|rt d |rt |}|r|d kr| jd||j |diq| jdd|iin| jdd|j |ii|t d| | f| d}|j|j|| d|iigS)Nr'rWrY)TFrr)r*r)r,r-z==)r.r/r0rHrr)r rr r;rz nat_%s_%s)r]r~rmr}rZ)rMrrrr2rrrrrrrrrrr)rTrrrr,toaddrtoportr]rr~rrrrrZr4r4r5$_build_policy_forward_port_nat_ruless4     z-nftables._build_policy_forward_port_nat_rulesc Csg}|rF|jr|jdks&|rFtd|rF|j|j||||||d|n|r|jrZ|jdksh|rtd|r|j|j||||||d|nL|rtd|r|j|j||||||d|n|j|j||||||d||S)NrHrLrGrK)r]rrr*) rTrrrr,r)r(rrr4r4r5build_policy_forward_port_ruless    z(nftables.build_policy_forward_port_rulescCs2|t|krt||Sttd||j|fdS)Nz)ICMP type '%s' not supported by %s for %s)rr r r)rTrZ icmp_typer4r4r5_icmp_types_to_nft_fragments(s  z%nftables._icmp_types_to_nft_fragmentscCsBd}|jjj||t}ddd|}|r6|jr6|j}n<|jrjg}d|jkrT|jdd|jkrr|jdnddg}g} x|D]} |jjj|rd||f} ddi} nd ||f} |j} g} |r| j|j |j | j|j |j| j|j |j | j|j| |j|r| j|j||||| | j|j||||| |jrf| j|j||||| nN|j|}d td |||f| |jgd }|j|j|| j|d |iiq~|jjdkr|jjj| r| j|d d t| | |j|jjddd||fiigd ii| j|d d t| | | gd iiq~W| S)Nr(rWrY)TFrGrHz %s_%s_allowrz %s_%s_denyrJz%s_%s_%s)r]r~rmr}rZrrrz"%s_%s_ICMP_BLOCK: ")rMrrripvsrr2query_icmp_block_inversionrrr]rrrrr,rrrrrrrrrrr)rTrrZictrr~rrr-rrZ final_chainrrrrZr4r4r5build_policy_icmp_block_rules/sb          " " z&nftables.build_policy_icmp_block_rulescCsd}|jjj||t}g}ddd|}|jjj|r@|j}nddi}|j|ddtd||fd |j|gd ii|jj d kr|jjj|r|j|ddtd||fd |j|j |jj d d d||fiigd ii|S)Nr(rWrY)TFrrZrJz%s_%sr9)r]r~rmrar}rrrz%s_%s_ICMP_BLOCK: ) rMrrrr.rr2rrrr)rTrrr~rrrrr4r4r5'build_policy_icmp_block_inversion_rulesks,      z0nftables.build_policy_icmp_block_inversion_rulesc Csg}ddddiidddiddd d d gd d idddig}|dkrV|jdddii|jddi|jdddtd|dii|jdddtddddddiddddgidid digdii|S)!Nr)rr`rz==rH)r.r/r0ZfibrZiifrZoif)flagsresultFrrrzrpfilter_DROP: rrXrZrJZfilter_PREROUTING)r]r~rmr}r*rFr+)r,r-rznd-router-advertznd-neighbor-solicitr)r2r)rTrrrr4r4r5build_rpfilter_ruless0     znftables.build_rpfilter_rulesc Csddddddddd g }d d |D}d d dddidd|idig}|jjd"krb|jdddii|j|jdg}|jdddtdd|dii|jdddtd d!|dii|S)#Nz ::0.0.0.0/96z::ffff:0.0.0.0/96z2002:0000::/24z2002:0a00::/24z2002:7f00::/24z2002:ac10::/28z2002:c0a8::/32z2002:a9fe::/32z2002:e000::/19cSs2g|]*}d|jddt|jdddiqS)rrrr<)r re)rrn).0r^r4r4r5 sz5nftables.build_rfc3964_ipv4_rules..r)r*rLr)r,r-z==r)r.r/r0rrrrzRFC3964_IPv4_REJECT: z addr-unreachrWrZrJrr<)r]r~rmrar}Zfilter_FORWARDrB)rr)rMZ _log_deniedr2rr)rTZ daddr_setrrr4r4r5build_rfc3964_ipv4_ruless:   z!nftables.build_rfc3964_ipv4_rulescCsd}g}|j|j|j|j|j|j|j|j|jg}|j|j||||||j|j||||||j|j ||||||S)Nr() r2rr]rrrrrrr)rTrrrr~rrr4r4r5*build_policy_rich_source_destination_rulessz3nftables.build_policy_rich_source_destination_rulescCs|dkr dSdS)NrGrHebTF)rGrHr8r4)rTrr4r4r5is_ipv_supportedsznftables.is_ipv_supportedc Csddd}||||ddg||dd||g||dd||g||dg||||||g||ddg||dd||g||dgdd }||kr||Sttd |dS) NZ ipv4_addrZ ipv6_addr)rGrHZ inet_protoZ inet_servicerZifnameZ ether_addr) zhash:ipz hash:ip,portzhash:ip,port,ipzhash:ip,port,netz hash:ip,markzhash:netz hash:net,netz hash:net,portzhash:net,port,netzhash:net,ifacezhash:macz!ipset type name '%s' is not valid)r r )rTrr+Zipv_addrtypesr4r4r5_set_type_lists"    znftables._set_type_listc Cs|rd|kr|ddkrd}nd}t||j||d}x0|jddjdD]}|dkrLd g|d <PqLW|rd|kr|d|d<d|kr|d|d<g}x0dD](}d|i} | j||jdd| iiqW|S)Nr]inet6rHrG)r~rr+:r<,rKnetrZintervalr1ZtimeoutZmaxelemsizerJrLrWr)rKr?r)rJrKrL)rr;rrr2) rTrr+optionsrZset_dicttrr]Z rule_dictr4r4r5build_set_create_ruless*     znftables.build_set_create_rulescCs$|j|||}|j||jjdS)N)rCrrMr)rTrr+rArr4r4r5 set_createsznftables.set_createcCs8x2dD]*}dd|t|dii}|j||jjqWdS)NrJrKrLrYr)r]r~r)rJrKrL)rrrMr)rTrr]rZr4r4r5 set_destroys   znftables.set_destroycCs6|jjj|jjddjd}g}xtt|D]}||dkrr|jdddii|jdd |rdd nd d iq2||dkr|jd|j||rdndd iq2||dkr|jdd|rdndiiq2||dkr|jdddiiq2t d||q2Wdt|dkrd|in|d|r&dndd|diS)Nr=r<r>rrr`rr*Zthrr")r,r-rKr?rrrZifacerrrz-Unsupported ipset type for match fragment: %sr)concatrz!=z==@)r.r/r0)rKr?r) rMr get_ipsetr+rrrer2rr )rTrZ match_destr type_formatr3ir4r4r5r  s$      znftables._set_match_fragmentc CsN|jjj|}|jjddjd}|jd}t|t|krHttdg}xtt|D]}||dkr,y||j d}Wn&t k r|j d||} Yn,X|j ||d||||dd} y| j d}Wn t k r|j | Yn(X|j d| d|| |ddgiq\||dkr d||krb|j d||jdiny||j d }WnLt k r||} d |j kr|j d d krt | } |j | Yn^X||d|} d |j kr|j d d krt | } |j d| t|||dddiq\|j ||q\Wt|dkrJd|igS|S)Nr=r<r>z+Number of values does not match ipset type.rZtcp-rrKr?rr]r<r)r rerF)rKr?)rMrrHr+rrer rrrarr2rArrn) rTrentryobjrIZ entry_tokensZfragmentrJraZport_strr r4r4r5_set_entry_fragment7sL  ("znftables._set_entry_fragmentc Cs>g}|j||}x(dD] }|jdd|t||diiqW|S)NrJrKrLrWr)r]r~relem)rJrKrL)rNr2r)rTrrLrrr]r4r4r5build_set_add_rulesks   znftables.build_set_add_rulescCs"|j||}|j||jjdS)N)rPrrMr)rTrrLrr4r4r5set_addus znftables.set_addcCsF|j||}x4dD],}dd|t||dii}|j||jjqWdS)NrJrKrLrYr)r]r~rrO)rJrKrL)rNrrrMr)rTrrLrr]rZr4r4r5 set_deleteys   znftables.set_deletecCs4g}x*dD]"}dd|t|dii}|j|q W|S)NrJrKrLr{r)r]r~r)rJrKrL)rr2)rTrrr]rZr4r4r5build_set_flush_ruless  znftables.build_set_flush_rulescCs |j|}|j||jjdS)N)rSrrMr)rTrrr4r4r5 set_flushs znftables.set_flushcCsJ|jjj|}|jdkrd}n(|jrBd|jkrB|jddkrBd}nd}|S)Nzhash:macr r]r<rLrK)rMrrHr+rA)rTrrr]r4r4r5rs znftables._set_get_familyc Csg}|j|j||||j|j|d}x^|D]D}|j|j|||d7}|dkr2|j||jj|jd}q2W|j||jjdS)Nrr<i)rrCrSrPrrMrclear) rTZset_nameZ type_nameZentriesZcreate_optionsZ entry_optionsrchunkrLr4r4r5 set_restores znftables.set_restore)N)N)r)rJ)FrJ)rJ)rJ)F)NN)NN)NN)NN)N)N)N)N)N)F)N)N)F)NN)I__name__ __module__ __qualname__rZpolicies_supportedrVrhrlrtrzrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr r!r#r$r%r&r'r*r+r,r/r0r3r6r7r9r;rCrDrEr rNrPrQrRrSrTrrWr4r4r4r5rIs/.`  4  R i ; - 9   +     $ $ $   ' $  < #   4   rIiji)N)(Z __future__rrirwr Zfirewall.core.loggerrZfirewall.functionsrrrrrZfirewall.errorsr r r r r rrZfirewall.core.richrrrrrrrZnftables.nftablesrrrrrrr6robjectrIr4r4r4r5s  $$                                         PKpge[__$__pycache__/ipXtables.cpython-36.pycnu[3 g@s(ddlZddlZddlmZddlmZddlmZm Z m Z m Z m Z m Z mZmZddlmZddlmZmZmZmZmZddlmZmZmZmZmZmZmZddl Z dZ!d d d gd d gd d d d d gd d d gd d d gdZ"dddZ#dddZ$ddZ%ddZ&ddZ'Gddde(Z)Gddde)Z*dS)N)runProg)log)tempFilereadfile splitArgs check_macportStrcheck_single_address check_address normalizeIP6)config) FirewallErrorINVALID_PASSTHROUGH INVALID_RULE UNKNOWN_ERROR INVALID_ADDR) Rich_Accept Rich_Reject Rich_Drop Rich_MarkRich_MasqueradeRich_ForwardPortRich_IcmpBlockINPUTOUTPUTFORWARD PREROUTING POSTROUTING)securityrawmanglenatfilterzicmp-host-prohibitedzicmp6-adm-prohibited)ipv4ipv6icmpz ipv6-icmpcCsddddddd}|dd}x~|D]v}y|j|}Wntk rLw$YnX|d kryt||d Wntk r~YnX|j|d ||||<q$W|S) z Inverse valid rule z-Dz--deletez-Xz--delete-chain)z-Az--appendz-Iz--insertz-Nz --new-chainN-I--insert)r'r()index Exceptionintpop)args replace_argsret_argsargidxr3/usr/lib/python3.6/ipXtables.pycommon_reverse_rule9s(  r5cCsddddddd}|dd}x|D]x}y|j|}Wntk rLw$YnX|d kryt||d Wntk r~YnX|j|d ||||<|SWttd dS) z Reverse valid passthough rule z-Dz--deletez-Xz--delete-chain)z-Az--appendz-Iz--insertz-Nz --new-chainN-I--insertr)zno '-A', '-I' or '-N' arg)r6r7)r* ValueErrorr,r-r r)r.r/r0xr2r3r3r4common_reverse_passthrough^s,   r:cCst|}tddddddddd d d d d dddddddg}t||@dkrbttdt||@dtddddddg}t||@dkrttddS)zZ Check if passthough rule is valid (only add, insert and new chain rules are allowed) z-Cz--checkz-Dz--deletez-Rz --replacez-Lz--listz-Sz --list-rulesz-Fz--flushz-Zz--zeroz-Xz--delete-chainz-Pz--policyz-Ez--rename-chainrzarg '%s' is not allowedz-Az--appendz-Iz--insertz-Nz --new-chainzno '-A', '-I' or '-N' argN)setlenr rlist)r.Z not_allowedZneededr3r3r4common_check_passthroughs*  r>c@seZdZdZdZdZddZddZddZd d Z d d Z d dZ ddZ ddZ ddZddZddZddZddZddZdd Zdhd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zdid,d-Zd.d/Zdjd1d2Zd3d4Zd5d6Zdkd8d9Zdld:d;Z dd?Z"d@dAZ#dBdCZ$dDdEZ%dFdGZ&dHdIZ'dJdKZ(dLdMZ)dNdOZ*dPdQZ+dmdRdSZ,dndTdUZ-dodVdWZ.dXdYZ/dpdZd[Z0dqd\d]Z1drd^d_Z2dsd`daZ3dbdcZ4dddeZ5dfdgZ6d!S)t ip4tablesr$TcCsd||_tj|j|_tjd|j|_|j|_|j|_ |j g|_ i|_ i|_ g|_i|_dS)Nz %s-restore)_fwr ZCOMMANDSipv_command_restore_command_detect_wait_option wait_option_detect_restore_wait_optionrestore_wait_option fill_existsavailable_tablesrich_rule_priority_countspolicy_priority_countszone_source_index_cache our_chains)selffwr3r3r4__init__s  zip4tables.__init__cCs$tjj|j|_tjj|j|_dS)N)ospathexistsrBZcommand_existsrCZrestore_command_exists)rNr3r3r4rHszip4tables.fill_existscCs|jr(|j|kr(|jgdd|D}ndd|D}tjd|j|jdj|t|j|\}}|dkrtd|jdj||f|S)NcSsg|] }d|qS)z%sr3).0itemr3r3r4 sz#ip4tables.__run..cSsg|] }d|qS)z%sr3)rTrUr3r3r4rVsz %s: %s %s rz'%s %s' failed: %s)rErdebug2 __class__rBjoinrr8)rNr.Z_argsstatusretr3r3r4Z__runszip4tables.__runc Cs<y|j|}Wntk r"dSX||||d<dSdS)NFT)r*r8)rNrulepatternZ replacementir3r3r4 _rule_replaces zip4tables._rule_replacecCs|tko|t|kS)N)BUILT_IN_CHAINS)rNrAtablechainr3r3r4is_chain_builtinszip4tables.is_chain_builtincCs2d|g}|r|jdn |jd|j||gS)Nz-tz-Nz-X)append)rNaddrcrdr^r3r3r4build_chain_ruless    zip4tables.build_chain_rulescCs8d|g}|r |d|t|g7}n |d|g7}||7}|S)Nz-tz-Iz-D)str)rNrgrcrdr*r.r^r3r3r4 build_rules  zip4tables.build_rulecCst|S)N)r5)rNr.r3r3r4 reverse_ruleszip4tables.reverse_rulecCs t|dS)N)r>)rNr.r3r3r4check_passthroughszip4tables.check_passthroughcCst|S)N)r:)rNr.r3r3r4reverse_passthroughszip4tables.reverse_passthroughcCsd}y|jd}Wntk r&YnXt||dkrD||d}d}xLd D]D}y|j|}Wntk rtYqNXt||dkrN||d}qNW||fS) Nr#z-tr]-A--append-I--insert-N --new-chain)rnrorprqrrrs)r*r8r<)rNr.rcr`rdoptr3r3r4passthrough_parse_table_chains$ z'ip4tables.passthrough_parse_table_chaincCs4yH|jd}|j||j|}d|dkr:||df}n ||df}WnFtk ry|jd}|j|d}Wntk rdSXYnXd}|ddkrd }|r| r||kr|j|nn|r0|r||kr|j||jd d d|j|}n|jjr d}nt|}d|d<|j dd|ddS)Nz%%ZONE_SOURCE%%z-mz%%ZONE_INTERFACE%%Tr-D--deleteFcSs|dS)Nrr3)r9r3r3r4&sz4ip4tables._run_replace_zone_source..)keyz-Ir)z%dr])ryrz) r*r-r8removerfsortr@_allow_zone_driftingr<insert)rNr^rLr`zoneZ zone_sourcerule_addr*r3r3r4_run_replace_zone_source s>             z"ip4tables._run_replace_zone_sourcecCsy|j|}Wntk r$YnXd}d}d}|j||j|}t|tkr\ttdd} xLdD]D} y|j| } Wntk rYqfXt|| dkrf|| d} qfWxhdD]`} y|j| }Wntk rYqXt||dkr||d} | dkrd}| dkrd}qW| | f} |sp| |ksP||| ksP|| |dkrZttd|| |d8<n| |kri|| <||| krd|| |<d} xHt || j D]4}||kr|rP| || |7} ||krPqW|| |d7<d ||<|j |dd| dS)a Change something like -t filter -I public_IN %%RICH_RULE_PRIORITY%% 123 or -t filter -A public_IN %%RICH_RULE_PRIORITY%% 321 into -t filter -I public_IN 4 or -t filter -I public_IN TFr]z%priority must be followed by a numberr#-t--table-A--append-I--insert-D--deleterz*nonexistent or underflow of priority countr)z%dN)rr)rrrrrr)rr)rr) r*r8r-typer,r rr<rsortedkeysr)rNr^Zpriority_countstokenr`rrZinsert_add_indexpriorityrcrtjrdr*pr3r3r4_set_rule_replace_priority2sj             z$ip4tables._set_rule_replace_prioritycCsPt}i}tj|j}tj|j}tj|j}x|D]}|dd} |j| dddt|jg|j| dt |jgy| j d} Wnt k rYn8X|dkrq6|d$krd d d |g| | | d <n | j | |j | |d|j | |d|j| |d} xZd%D]R} y| j | } Wnt k r,Yn(Xt| | d kr| j | | j | } qWxhtt| D]X} xPtjD]F} | | | krt| | jdo| | jd rtd| | | | <qtWqhW|j| gj| q6WxR|D]J} || }|jd| x"|D]} |jdj| dqW|jdqW|jtj|j}tjd|j|j d|j|j!fg}|j"rz|j|j"|jdt#|j ||jd\}}tj$dkr t%|j}|dk r d } xH|D]@}tj&d| |fd dd |jdstj&d!d d"| d 7} qWtj'|j|dkr:t d#|j dj||f||_||_||_dS)&Nz %%REJECT%%REJECTz --reject-withz%%ICMP%%z %%LOGTYPE%%offunicast broadcast multicastz-mpkttypez --pkt-typer]z%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%r#-t--table"z"%s"z*%s rW zCOMMIT z %s: %s %sz%s: %dz-n)stdinr)z%8d: %sr)nofmtnlr)rz'%s %s' failed: %s)rrr)rr)(rcopydeepcopyrJrKrLraDEFAULT_REJECT_TYPErAICMPr*r8r-rrr<rangestringZ whitespace startswithendswith setdefaultrfwriterZcloserQstatnamerrXrYrCst_sizerGrZgetDebugLogLevelrZdebug3unlink)rNrules log_denied temp_fileZ table_rulesrJrKrLZ_ruler^r`rcrtcrr.r[r\linesliner3r3r4 set_ruless                    zip4tables.set_rulesc Cs|j|dddt|jg|j|dt|jgy|jd}Wntk rRYn:X|dkr`dS|dkrd d d |g|||d<n |j|tj|j }tj|j }tj|j }|j ||d|j ||d|j |||j|}||_ ||_ ||_ |S)Nz %%REJECT%%rz --reject-withz%%ICMP%%z %%LOGTYPE%%rrrrrz-mrz --pkt-typer]z%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%)rrr)rarrArr*r8r-rrrJrKrLrr_ip4tables__run)rNr^rr`rJrKrLoutputr3r3r4set_rules.      zip4tables.set_ruleNc Csg}|r|gntj}xx|D]p}||jkr6|j|qy,|jd|ddg|jj||j|Wqtk rtjd|j|fYqXqW|S)Nz-tz-Lz-nzA%s table '%s' does not exist (or not enough permission to check).) rbrrIrfrr8rdebug1rA)rNrcr\Ztablesr3r3r4get_available_tabless    zip4tables.get_available_tablescCs`d}t|jdddg}|ddkr\d}t|jdddg}|ddkrHd}tjd|j|j||S)Nrz-wz-Lz-nrz-w10z%s: %s will be using %s option.)rrBrrXrY)rNrEr\r3r3r4rDs  zip4tables._detect_wait_optioncCst}|jd|jd}xJd D]B}t|j|g|jd}|ddkr"d|dkr"d |dkr"|}Pq"Wtjd |j|j|t j |j|S) Nz#foor-w--wait=2)rrzinvalid optionr]zunrecognized optionz%s: %s will be using %s option.)rr) rrrrrCrrrXrYrQr)rNrrEZ test_optionr\r3r3r4rF"s    z%ip4tables._detect_restore_wait_optioncCsVi|_i|_g|_g}x:tjD].}|j|s0q xdD]}|jd||gq6Wq W|S)N-F-X-Zz-t)rrr)rJrKrLrbrrrf)rNrrcflagr3r3r4build_flush_rules5s  zip4tables.build_flush_rulescCsfg}|dkrdn|}xLtjD]@}|j|s.q|dkr8qx$t|D]}|jd|d||gqBWqW|S)NZPANICDROPr"z-tz-P)rbrrrf)rNpolicyr_policyrcrdr3r3r4build_set_policy_rulesDs z ip4tables.build_set_policy_rulesc Cs g}d}y"|jd|jdkrdnddg}WnJtk rt}z.|jdkrVtjd|ntjd|WYd d }~XnX|j}d }x|D]}|r|jj}|j}xD|D]<} | j d r| j d r| d d} n| } | |kr|j | qW|jdko|j ds|jdkr|j drd}qW|S)zQReturn ICMP types that are supported by the iptables/ip6tables command and kernelrz-pr$r&z ipv6-icmpz--helpziptables error: %szip6tables error: %sNF()r]zValid ICMP Types:r%zValid ICMPv6 Types:Tr) rrAr8rr splitlinesstriplowersplitrrrf) rNrAr\rZexrZin_typesrZsplitsrr9r3r3r4supported_icmp_typesPs4      zip4tables.supported_icmp_typescCsgS)Nr3)rNr3r3r4build_default_tablesqszip4tables.build_default_tablesrc Csi}|jdrpg|d<t|jd<xLtdD]@}|djd||djd||f|jdjd|q,W|jdr\g|d<t|jd<xtdD]}|djd||djd||f|jdjd||dkrxt|jjrddd d gndd d gD]R}|djd ||f|djd |||f|jdjtd ||fgqWqW|jdrNg|d<t|jd<xtdD]}|djd||djd||f|jdjd||dkrxv|jjrddd d gndd d gD]R}|djd ||f|djd |||f|jdjtd ||fgqWqW|jdr@g|d<t|jd<xtdD]}|djd||djd||f|jdjd||d9krxxv|jjrddd d gndd d gD]R}|djd ||f|djd |||f|jdjtd ||fgqWqxWg|d<t|jd<|djd|djd|djd|djd|jdjtdxf|jjrddd d gndd d gD]B}|djd||djd||jdjtd|qW|dkr |djd|djd|dkrF|djd|djd|djd|djd |djd!|djd"|jdjtd#xJd:D]B}|djd$||djd%||jdjtd&|qWxzd;D]r}xj|jjr dd gnd gD]N}|djd)||f|djd*||f|jdjtd+||fqWqWxJdD]B}|djd5||djd6||jdjtd7|q~Wg}xJ|D]B}||jkrqx(||D]}|jd8|gt |qWqW|S)?Nrz -N %s_directz-A %s -j %s_directz %s_directr r POLICIES_preZ ZONES_SOURCEZZONES POLICIES_postz-N %s_%sz-A %s -j %s_%sz%s_%sr!r"rr#zB-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPTz-A INPUT -i lo -j ACCEPTz-N INPUT_directz-A INPUT -j INPUT_directZ INPUT_directz -N INPUT_%sz-A INPUT -j INPUT_%szINPUT_%srz^-A INPUT -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: 'z/-A INPUT -m conntrack --ctstate INVALID -j DROPz9-A INPUT %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: 'z-A INPUT -j %%REJECT%%zD-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPTz-A FORWARD -i lo -j ACCEPTz-N FORWARD_directz-A FORWARD -j FORWARD_directZFORWARD_directz -N FORWARD_%sz-A FORWARD -j FORWARD_%sz FORWARD_%sINOUTz-N FORWARD_%s_%sz-A FORWARD -j FORWARD_%s_%sz FORWARD_%s_%sz`-A FORWARD -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: 'z1-A FORWARD -m conntrack --ctstate INVALID -j DROPz;-A FORWARD %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: 'z-A FORWARD -j %%REJECT%%z-N OUTPUT_directz>-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPTz-A OUTPUT -o lo -j ACCEPTz-A OUTPUT -j OUTPUT_directZ OUTPUT_directz -N OUTPUT_%sz-A OUTPUT -j OUTPUT_%sz OUTPUT_%sz-t)rr)r)rr)r)r)r) rr;rMrbrfrgr@rupdater) rNrZ default_rulesrdZdispatch_suffix directionZfinal_default_rulesrcr^r3r3r4build_default_rulesus    $(   &*   &* &    (       "zip4tables.build_default_rulescCsf|dkrdddhS|dkr,d|jkr,dhS|dkrHd|jkrHddhS|d krbd |jkrbdhSiS) Nr#r FORWARD_IN FORWARD_OUTr!rr"rr )r)rNrcr3r3r4get_zone_table_chainss    zip4tables.get_zone_table_chainsc s|jjj|jdkrdnddkr4dkr4dnd} |jjj|t| g} g} x|D]} | jd| gqZWx|D]} | jd | gqvWxB|D]:} |jjj| }|dkr|j | rq| j|j d | qWx\|D]T} |jjj| }|dkr|j | rqt | rdkrq| j|j d| qWfdd}g}| rx| D]F}| rx8| D]}|j|||qdWn|rn|j||dqTWnH|rn@| rx8| D]}|j|d|qWn|rn|j|dd|S)Nrprepostr"rTFz-iz-or$r%z-srrz-dcsVddd}d|dfdjg}|r6|j||rD|j||jdg|S)Nz-Az-D)TFz-tz%s_POLICIES_%sz%%POLICY_PRIORITY%%z-j)rextend)ingress_fragmentegress_fragmentadd_delr^)rrd chain_suffixenablep_objrcr3r4_generate_policy_dispatch_rules   zSip4tables.build_policy_ingress_egress_rules.._generate_policy_dispatch_rule)r$r%)r$r%)rrr) r@rZ get_policyrpolicy_base_chain_namePOLICY_CHAIN_PREFIXrfrZ check_sourceis_ipv_supported_rule_addr_fragmentr)rNrrrcrdZingress_interfacesZegress_interfacesZingress_sourcesZegress_sourcesisSNATZingress_fragmentsZegress_fragments interfaceaddrrArrrrr3)rrdrrrrcr4!build_policy_ingress_egress_rulessR        z+ip4tables.build_policy_ingress_egress_rulesFc Cs|dkr|dkrdnd}|jjj||t|d} ddddddd|} d } |rb| rbd d |d g} n,|rtd d |g} ndd |g} |s| d g7} | d|| || | g7} | gS)Nr"rTF)rz-iz-o)rrrrrrz-gz-Iz%s_ZONESz%%ZONE_INTERFACE%%z-Az-Dz-t)r@rrr) rNrrrrrcrdrfrrrtactionr^r3r3r4!build_zone_source_interface_rulesKs&   z+ip4tables.build_zone_source_interface_rulescCs|jdrP|dd}|dkr$d}nd}dj|g|jjj|}ddd ||gSt|rz|dkrjttd dd d |jgSt d |rt |}n,t d |r|j d}t |dd|d}||gSdS)Nzipset:z-ddstsrc,z-mr;z --match-setzCan't match a destination MAC.macz --mac-sourcer%/rr]) rrZr@ipsetZ get_dimensionrr rupperr r r r)rNrtaddressinvertrflags addr_splitr3r3r4res"       zip4tables._rule_addr_fragmentc Csddd|}|dkr"|dkr"dnd}|jjj||t|d} d d d d d d d |} |jjrdd |} nd |} t|r|dkrgS|| d|d|g} | j|j| || jd| g| gS)Nz-Iz-D)TFr"rTF)rz-sz-d)rrrrrrz%s_ZONES_SOURCEz%s_ZONESrrz%%ZONE_SOURCE%%z-tz-g)rrr)r@rrrrrrr) rNrrrrrcrdrrrrtZzone_dispatch_chainr^r3r3r4build_zone_source_address_rules{s& z)ip4tables.build_zone_source_address_rulesc Cs>ddd|}ddd|}|dkr0|dkr0dnd }|jjj||t|d }|j|jt|d |d |d |d|d|gg} | j||d|g| j|d |d|g| j|d |d|g| j|d |d|g| j|d|d|g| j|d|d|g| j||d|dd |g| j||d|dd |g| j||d|dd |g| j||d|dd|g| j||d|dd|g|jjj|j } |jj dkr|dkr| dkr| j||d|ddddd|g | dkr| j||d|ddddd|g |dkr,| dkr,| j||d|d| g|s:| j | S)Nz-Nz-X)TFz-Az-Dr"rTF)rz%s_logz%s_denyz%s_prez%s_postz%s_allowz-tz-jrr#r %%REJECT%%z %%LOGTYPE%%LOGz --log-prefixz "%s_REJECT: "rz "%s_DROP: "ACCEPT)rr)rrrr) r@rrrrMrr;rfZ _policiestargetget_log_deniedreverse) rNrrrcrdZ add_del_chainZ add_del_rulerrrrr3r3r4build_policy_chain_rulessN       z"ip4tables.build_policy_chain_rulescCs2|sgSddd|jg}|jdk r.|d|jg7}|S)Nz-mlimitz--limitz --limit-burst)valueZburst)rNrsr3r3r4 _rule_limits  zip4tables._rule_limitcCst|jtttgkrn<|jrHt|jtttt gkrRt t dt|jn t t d|j dkrt|jttgkst|jtt gkrdSt|jtgkst|jttgkrdSn|j dkrdSdSdS)NzUnknown action %szNo rule action specified.rallowZdenyrr) relementrrrrrrrrr rr)rN rich_ruler3r3r4_rich_rule_chain_suffixs    z!ip4tables._rich_rule_chain_suffixcCs>|j r|j rttd|jdkr(dS|jdkr6dSdSdS)NzNot log or auditrrrr)rauditr rr)rNrr3r3r4 _rich_rule_chain_suffix_from_logs   z*ip4tables._rich_rule_chain_suffix_from_logcCs|jdkrgSd|jgS)Nrz%%RICH_RULE_PRIORITY%%)r)rNrr3r3r4_rich_rule_priority_fragments z&ip4tables._rich_rule_priority_fragmentc Cs|js gS|jjj||t}ddd|}|j|}d||d||fg} | |j|7} | |ddg7} |jjr| dd |jjg7} |jjr| d d |jjg7} | |j |jj 7} | S) Nz-Az-D)TFz-tz%s_%sz-jrz --log-prefixz'%s'z --log-levelz%s) rr@rrrr r prefixlevelrr) rNrrrrc rule_fragmentrrrr^r3r3r4_rich_rule_logs zip4tables._rich_rule_logc Cs|js gSddd|}|jjj||t}|j|}d||d||fg} | |j|7} | |7} t|jt krrd} n,t|jt krd} nt|jt krd} nd } | d d d | g7} | |j |jj 7} | S) Nz-Az-D)TFz-tz%s_%sZacceptZrejectZdropunknownz-jZAUDITz--type)r r@rrrr r rrrrrrr) rNrrrrcrrrrr^Z_typer3r3r4_rich_rule_audit s$ zip4tables._rich_rule_auditc Cs2|js gSddd|}|jjj||t}|j|}d||f} t|jtkrXddg} nt|jtkrddg} |jjr| d|jjg7} nnt|jt krdd g} nVt|jt krd }|jjj||t}d||f} dd d |jj g} nt t d t|jd||| g} | |j|7} | || 7} | |j|jj7} | S)Nz-Az-D)TFz%s_%sz-jrrz --reject-withrr!MARKz --set-xmarkzUnknown action %sz-t)rr@rrrr rrrrrr;r rr rr) rNrrrrcrrrrrdZ rule_actionr^r3r3r4_rich_rule_action$s4       zip4tables._rich_rule_actioncCs|sgSg}|jr|jr"|jdtd|jrB|dt|jg7}qtd|jr||jjd}|dt|dd|dg7}q|d|jg7}nD|jr|ddg7}|jr|jd|jj j |jd }|d |j|g7}|S) N!r%z-drrr]z-mr;rz --match-set) rrrfr r r rrr@r_ipset_match_flags)rNZ rich_destrrrr3r3r4_rich_rule_destination_fragmentFs&    "  z)ip4tables._rich_rule_destination_fragmentcCs|sgSg}|jr|jr"|jdtd|jrB|dt|jg7}nHtd|jr||jjd}|dt|dd|dg7}n|d|jg7}nt|dr|jr|ddg7}|jr|jd|d |jg7}nPt|d o|j r|dd g7}|jr|jd|j j j |j d }|d |j |g7}|S)Nrr%z-srrr]rz-mz --mac-sourcerr;rz --match-set) rrrfr r r rhasattrrrr@rr)rNZ rich_sourcerrrr3r3r4_rich_rule_source_fragment^s0    "    z$ip4tables._rich_rule_source_fragmentc Csddd|}d}|jjj||t} d|g} |rD| ddt|g7} |rT| d|g7} |rx| |j|j7} | |j|j7} | st |j t kr| d d d d g7} g} |r| j |j ||||| | j |j||||| | j |j||||| n"| j |d | d|g| ddg| S)Nz-Az-D)TFr#z-pz--dportz%sz-dz-m conntrackz --ctstatez NEW,UNTRACKEDz%s_allowz-tz-jr)r@rrrrr destinationrsourcerrrrfrrr) rNrrprotoportrrrrcrrrr3r3r4build_policy_ports_rules{s* z"ip4tables.build_policy_ports_rulesc Csddd|}d}|jjj||t}d|g} |r<| d|g7} |r`| |j|j7} | |j|j7} | stt|j t kr| ddd d g7} g} |r| j |j ||||| | j |j ||||| | j |j||||| n"| j |d |d |g| d dg| S)Nz-Az-D)TFr#z-pz-dz-mrz --ctstatez NEW,UNTRACKEDz%s_allowz-tz-jr)r@rrrrrrrrrrrfrrr) rNrrprotocolrrrrcrrrr3r3r4build_policy_protocol_ruless& z%ip4tables.build_policy_protocol_rulesc Csddd|}d}|jjj||t} d|g} |rD| ddt|g7} |rT| d|g7} |rx| |j|j7} | |j|j7} | st |j t kr| d d d d g7} g} |r| j |j ||||| | j |j||||| | j |j||||| n"| j |d | d|g| ddg| S)Nz-Az-D)TFr#z-pz--sportz%sz-dz-mrz --ctstatez NEW,UNTRACKEDz%s_allowz-tz-jr)r@rrrrrrrrrrrrfrrr) rNrrrrrrrrcrrrr3r3r4build_policy_source_ports_ruless* z)ip4tables.build_policy_source_ports_rulesc Csvd}|jjj||t} ddd|} | d| ddd|g} |rP| dd t|g7} |r`| d |g7} | d d d |g7} | gS)Nr z-Az-D)TFz%s_allowz-tz-pz--dportz%sz-dz-jZCTz--helper)r@rrrr) rNrrrrrZ helper_nameZmodule_short_namercrrr^r3r3r4build_policy_helper_ports_ruless z)ip4tables.build_policy_helper_ports_rulesc Csddd|}|jjj||t}g} |rH| jdd|d|d|dd gn6t|rTgS| jdd|d|g|jd |dd g| S) Nz-Az-D)TFz-tr#z%s_allowz-oz-jrz-d)r@rrrrfrr) rNrrrrcrrrrrr3r3r4build_zone_forward_ruless z"ip4tables.build_zone_forward_rulesc Cs,d}|jjj||tdd}ddd|}g}|rj|j|}||j|7}||j|j7}||j|j 7}nd}g} | j dd|d ||fg|d d d d dgg}|r|j|}||j|7}||j|j7}||j|j 7}nd}d}|jjj||t}| j dd|d ||fg|ddddd dg| S)Nr"T)rz-Az-D)TFrz-tz%s_%srz-oloz-jZ MASQUERADEr#z-mrz --ctstatez NEW,UNTRACKEDr) r@rrrr r rrrrrf) rNrrrrcrrrrrr3r3r4build_policy_masquerade_ruless6  z'ip4tables.build_policy_masquerade_rulesc Cs d}|jjj||t} ddd|} d} |rPtd|rH| dt|7} n| |7} |rn|dkrn| dt|d 7} g} |r|j|} |j|} | |j |j 7} | |j |j 7} nd } g}|r|j |j|||d| |j d d| d | | fg| d |dt|ddd| g|S)Nr"z-Az-D)TFrr%z[%s]z:%s-rz-tz%s_%sz-pz--dportz-jZDNATz--to-destination)r@rrrr r rr r rrrrrfr)rNrrrr ZtoportZtoaddrrrcrrZtorrrr3r3r4build_policy_forward_port_ruless2     z)ip4tables.build_policy_forward_port_rulescCsd}|jjj||t}ddd|}|jdkrFddg}ddd |jg} ndd g}dd d |jg} g} |jjj|r|d |} d} n d|} d} g} |r| |j|j7} | |j |j 7} | || 7} |rP| j |j ||||| | j |j ||||| |jr| j |j||||| n:|j|}| j d||d||fg|j|| ddgn`|jjdkr| dkr| j || d|g| ddddd|g| j || d|g| d| g| S)Nr#z-Az-D)TFr$z-pr&z-mz --icmp-typez ipv6-icmpZicmp6z --icmpv6-typez%s_allowrz%s_denyz %%REJECT%%z-tz%s_%sz-jrz %%LOGTYPE%%rz --log-prefixz"%s_ICMP_BLOCK: ")r@rrrrArquery_icmp_block_inversionrrrrrfrrrrr r r)rNrrZictrrcrrrmatchrZ final_chainZ final_targetrrr3r3r4build_policy_icmp_block_rules3sJ     z'ip4tables.build_policy_icmp_block_rulesc Csd}|jjj||t}g}d}|jjj|rd}|jjdkr|rRd|t|g}nd|g}|d|dd d d d d d|g }|j||d7}nd}|rd|t|g}nd|g}|d|dd d |g}|j||S)Nr#rz %%REJECT%%rz-Iz-Dz-tz-pz%%ICMP%%z %%LOGTYPE%%z-jrz --log-prefixz"%s_ICMP_BLOCK: "r]r)r@rrrr)rrirf) rNrrrcrrZrule_idxZ ibi_targetr^r3r3r4'build_policy_icmp_block_inversion_rulesds.     z1ip4tables.build_policy_icmp_block_inversion_rulescCsxd}g}||j|j7}||j|j7}g}|j|j||||||j|j||||||j|j||||||S)Nr#)rrrrrfrrr)rNrrrrcrrr3r3r4*build_policy_rich_source_destination_rulessz4ip4tables.build_policy_rich_source_destination_rulescCs ||jkS)N)rA)rNrAr3r3r4rszip4tables.is_ipv_supported)N)N)r)F)F)NN)NN)NN)NN)N)N)N)7__name__ __module__ __qualname__rArZpolicies_supportedrPrHrrarerhrjrkrlrmrurrrrrrDrFrrrrrrrrrrrrr r r rrrrrrr!r"r#r$r&r(r+r,r-rr3r3r3r4r?sh     )Pa#   ! zN  0 "     & ! 1"r?c@s&eZdZdZdZdddZddZdS) ip6tablesr%Fc Csg}|jddddddddd d g |d krL|jddddddddd d d dg |jdddddddd dg |jdddddddd dg |S)Nz-Irz-tr!z-mZrpfilterz--invertz --validmarkz-jrrrz --log-prefixzrpfilter_DROP: z-pz ipv6-icmpz$--icmpv6-type=neighbour-solicitationrz"--icmpv6-type=router-advertisement)rf)rNrrr3r3r4build_rpfilter_ruless$        zip6tables.build_rpfilter_rulesc Csddddddddd g }d }|jd j|g}|jd d d |gxT|D]L}|jd d d|d|ddddg |jjdkrF|jd d d|d|ddddg qFW|jd d dddd|g|jd d dddd|g|S)Nz ::0.0.0.0/96z::ffff:0.0.0.0/96z2002:0000::/24z2002:0a00::/24z2002:7f00::/24z2002:ac10::/28z2002:c0a8::/32z2002:a9fe::/32z2002:e000::/19Z RFC3964_IPv4r#z-tz-Nz-Iz-dz-jrz --reject-withz addr-unreachrallrz --log-prefixz"RFC3964_IPv4_REJECT: "r4r)rr3)rMrgrfr@Z _log_denied)rNZ daddr_listZ chain_namerZdaddrr3r3r4build_rfc3964_ipv4_ruless4       z"ip6tables.build_rfc3964_ipv4_rulesN)F)r.r/r0rArr2r5r3r3r3r4r1s r1)+Zos.pathrQrZfirewall.core.progrZfirewall.core.loggerrZfirewall.functionsrrrrrr r r Zfirewallr Zfirewall.errorsr rrrrZfirewall.core.richrrrrrrrrrrbrrr5r:r>objectr?r1r3r3r3r4s@  ( $ %* xPKpge[xMlMl#__pycache__/fw.cpython-36.opt-1.pycnu[3 g@sdgZddlZddlZddlZddlZddlZddlmZddlm Z ddl m Z ddl m Z ddl m Z ddl mZdd l mZdd lmZdd lmZdd lmZdd lmZddlmZddlmZddlmZddlmZddl m!Z!ddl"m#Z#ddl$m%Z%m&Z&ddl'm(Z(ddl)m*Z*ddl+m,Z,ddl-m.Z.ddl/m0Z0ddl1m2Z2m3Z3ddl4m5Z5ddl6m7Z7ddl8m9Z9ddl:m;Z;ddlmZ>Gd!dde?Z@dS)"FirewallN)config) functions) ipXtables)ebtables)nftables)ipset)modules)FirewallIcmpType)FirewallService) FirewallZone)FirewallDirect)FirewallConfig)FirewallPolicies) FirewallIPSet)FirewallTransaction)FirewallHelper)FirewallPolicy)nm_get_bus_namenm_get_interfaces_in_zone)log)firewalld_conf)Direct)service_reader)icmptype_reader) zone_readerZone) ipset_reader) IPSET_TYPES) helper_reader) policy_reader)errors) FirewallErrorc@seZdZdeddZddZddZdd Zd d Zdfd d ZddZ dgddZ ddZ ddZ ddZ ddZddZddZddZd d!Zd"d#Zd$d%Zd&d'Zdhd)d*Zdid+d,Zd-d.Zdjd/d0Zdkd1d2Zdld3d4Zd5d6Zd7d8Zd9d:Zd;d<Zd=d>Z d?d@Z!dAdBZ"dCdDZ#dEdFZ$dGdHZ%dIdJZ&dKdLZ'dMdNZ(dmdOdPZ)dQdRZ*dSdTZ+dUdVZ,dWdXZ-dYdZZ.d[d\Z/d]d^Z0d_d`Z1dadbZ2dcddZ3d(S)nrFcCsttj|_||_|jr>d|_d|_d|_d|_t |_ d|_ nrt j ||_d|_g|_t j||_d|_g|_tj|_d|_tj|_d|_g|_ tj||_d|_ tj|_t||_t||_t||_ t!||_"t#||_t$|_%t&||_t'||_(t)||_*|j+dS)NFT),rrFIREWALLD_CONF_firewalld_conf_offlineip4tables_enabledip6tables_enabledebtables_enabled ipset_enabledripset_supported_typesnftables_enabledr ip4tablesip4tables_backendipv4_supported_icmp_types ip6tablesip6tables_backendipv6_supported_icmp_typesrebtables_backendr ipset_backendrnftables_backendr modules_backendr icmptyper servicer zoner directrrpoliciesrrhelperrpolicy_Firewall__init_vars)selfZoffliner?/usr/lib/python3.6/fw.py__init__CsB               zFirewall.__init__cCsDd|j|j|j|j|j|j|j|j|j|j |j |j |j |j |jfS)Nz:%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)) __class__r&r'r(_state_panic _default_zone_module_refcount_markscleanup_on_exitcleanup_modules_on_exitipv6_rpfilter_enabledr)_individual_calls _log_denied)r>r?r?r@__repr__ks   zFirewall.__repr__cCsjd|_d|_d|_i|_g|_tj|_tj|_ tj |_ tj |_ tj|_tj|_tj|_tj|_tj|_dS)NZINITF)rCrDrErFrGrZFALLBACK_CLEANUP_ON_EXITrHZ FALLBACK_CLEANUP_MODULES_ON_EXITrIZFALLBACK_IPV6_RPFILTERrJZFALLBACK_INDIVIDUAL_CALLSrKZFALLBACK_LOG_DENIEDrLZFALLBACK_FIREWALL_BACKEND_firewall_backendZFALLBACK_FLUSH_ALL_ON_RELOAD_flush_all_on_reloadZFALLBACK_RFC3964_IPV4 _rfc3964_ipv4ZFALLBACK_ALLOW_ZONE_DRIFTING_allow_zone_drifting)r>r?r?r@Z __init_varstszFirewall.__init_varscCs|jr$d|jjkr$tjdd|_|jrHd|jjkrHtjdd|_|jrld|jjkrltjdd|_|j r|j r|j rtj dt j ddS)Nfilterziptables is not usable.Fzip6tables is not usable.zebtables is not usable.zNo IPv4 and IPv6 firewall.) r&r-get_available_tablesrinfo1r'r0r(r2r+fatalsysexit)r>r?r?r@ _check_tabless     zFirewall._check_tablesc Cszy|jjWn*tk r8tjdd|_g|_YnX|jj|_|jj |jj s||jj rltjdntjdd|_ |j r|jjd|_n|j r|jj|_ng|_|jj |jj s|jj rtjdntjdd|_|j r|jjd|_n|jr|jj|_ng|_|jj |jj sN|jj r>tjd ntjd d|_|jrv|j rv|jj rvtjd dS) Nz4ipset not usable, disabling ipset usage in firewall.FzFiptables-restore is missing, using individual calls for IPv4 firewall.zCiptables-restore and iptables are missing, disabling IPv4 firewall.ipv4zGip6tables-restore is missing, using individual calls for IPv6 firewall.zEip6tables-restore and ip6tables are missing, disabling IPv6 firewall.ipv6zHebtables-restore is missing, using individual calls for bridge firewall.zEebtables-restore and ebtables are missing, disabling bridge firewall.zSebtables-restore is not supporting the --noflush option, will therefore not be used)r3Zset_list ValueErrorrwarningr)r*Zset_supported_typesr-Z fill_existsrestore_command_existsZcommand_existsr&r+r4Zsupported_icmp_typesr.r0r'r1r2r(rKrestore_noflush_optiondebug1)r>r?r?r@ _start_checksL               zFirewall._start_checkc>Cstj}tjdtjy|jjWn8tk rZ}ztj|tjdWYdd}~Xn"X|jj drt|jj d}|jj dr|jj d}|dk r|j dBkrd|_ tjd|j |jj d r|jj d }|dk r|j dCkrd |_ |dk r|j dDkrd|_ tjd |j |jj drv|jj d}|dk rv|j dEkrvtjdy|j jWntk rtYnX|jj dr|jj d}|dk r|j dFkrd|_|j dGkrd |_|jrtjdn tjd|jj dr"|jj d}|dk r"|j dHkr"tjdd |_|jj drt|jj d}|dksT|j dkr\d|_n|j |_tjd|j|jj dr|jj d|_tjd|j|jj dr|jj d}|j dIkrd|_nd |_tjd|j|jj dr&|jj d}|j dJkrd|_nd |_tjd|j|jj dr||jj d}|j dKkrVd|_nd |_|jsntjdtjd |j|jjtj|j|j|j|js|jtjd!y|j jjWnZtk r }z<|j jrtjd"|j jj |ntjd"|j jj |WYdd}~XnX|jj!tj|j |j"tj#d#|j"tj$d#|j"tj%d$|j"tj&d$t'|j(j)d%krtjd&|j"tj*d'|j"tj+d'|j"tj,d(|j"tj-d(t'|j.j/d%krtjd)|j"tj0d*|j"tj1d*t'|j2j3d%kr&tj4d+t5j6d,|j"tj7d-|j"tj8d-d}x.dLD]&}||j2j3krLtj4d1|d }qLW|rt5j6d,||j2j3krd2|j2j3krd2}nd3|j2j3krd3}nd.}tjd4|||}n tjd5|t9tj:} t;jj?| |jj@tj| |jA||_B|jrdS|jCtjDd%krtEjE} tF|} |s|jG| d8|r|s|jHr|jIjJr| jKd | jL|r|rtjd9|jMjN|jO| d8| jKd | jL|jHrX|jIjJrXtjd:|jIjPtjd;|jQ| d8tjd<|j2jR| d8|j2jSd|jB| d8tjd=|jTjU| d8| jKd | jL|j>jVrVtjd>|j>jW| y| jKd | jLWnXtk r>} z$t| jXd?| jYr&| jYnd@WYdd} ~ Xntk rTYnX~ tjDd,krtEjE} tjZdA| | dS)MNz"Loading firewalld config file '%s'z0Using fallback firewalld configuration settings. DefaultZoneZ CleanupOnExitnofalseFzCleanupOnExit is set to '%s'ZCleanupModulesOnExityestrueTz#CleanupModulesOnExit is set to '%s'ZLockdownzLockdown is enabledZ IPv6_rpfilterzIPv6 rpfilter is enabledzIPV6 rpfilter is disabledZIndividualCallszIndividualCalls is enabled LogDeniedZoffzLogDenied is set to '%s'ZFirewallBackendzFirewallBackend is set to '%s'ZFlushAllOnReloadzFlushAllOnReload is set to '%s'Z RFC3964_IPv4zRFC3964_IPv4 is set to '%s'ZAllowZoneDriftingzAllowZoneDrifting is enabled. This is considered an insecure configuration option. It will be removed in a future release. Please consider disabling it now.z AllowZoneDrifting is set to '%s'zLoading lockdown whitelistz*Failed to load lockdown whitelist '%s': %srr6rzNo icmptypes found.r;r7zNo services found.r8zNo zones found.rTr<blockdroptrustedzZone '%s' is not available.ZpublicZexternalz+Default zone '%s' is not valid. Using '%s'.zUsing default zone '%s'zLoading direct rules file '%s'z)Failed to load direct rules file '%s': %s)use_transactionzUnloading firewall moduleszApplying ipsetszApplying default rule setzApplying used zoneszApplying used policiesz2Applying direct chains rules and passthrough rulesz Direct: %srNz%Flushing and applying took %f seconds)rdre)rfrg)rdre)rfrg)rdre)rfrg)rfrg)rdre)rdre)rdre)rirjrk)[rZ FALLBACK_ZONErrar#r$read Exceptionr^getlowerrHrIr:Zenable_lockdownr"rJrKrLrOrPrQrRr%Zset_firewalld_confcopydeepcopy_select_firewall_backendrbZlockdown_whitelistZquery_lockdownerrorfilenameZ set_policies_loaderZFIREWALLD_IPSETSZETC_FIREWALLD_IPSETSZFIREWALLD_ICMPTYPESZETC_FIREWALLD_ICMPTYPESlenr6 get_icmptypesZFIREWALLD_HELPERSZETC_FIREWALLD_HELPERSZFIREWALLD_SERVICESZETC_FIREWALLD_SERVICESr7 get_servicesZFIREWALLD_ZONESZETC_FIREWALLD_ZONESr8 get_zonesrWrXrYZFIREWALLD_POLICIESZETC_FIREWALLD_POLICIESrZFIREWALLD_DIRECTospathexistsr9Zset_permanent_configZ set_direct check_zonerErZZgetDebugLogLeveltimerflushr)rZ has_ipsetsexecuteclearr5unload_firewall_modulesapply_default_tablesZ apply_ipsetsapply_default_rulesZ apply_zoneschange_default_zoner<Zapply_policiesZhas_configurationZ apply_directcodemsgZdebug2)r>reloadcomplete_reloadZ default_zonervaluertzr8objZtm1 transactioneZtm2r?r?r@_startst                                                           .zFirewall._startc CsHy |jWn&tk r2d|_|jdYnXd|_|jddS)NFAILEDACCEPTRUNNING)rrnrC set_policy)r>r?r?r@starts  zFirewall.startc Cshtjj|sdS|rZ|jtjrV|dkrVt}tjj||_|j |j||_d|_ nd}x|t tj |D]h}|j ds|jtjrl|dkrltjjd||frl|jd||f|ddqld||f}tjd||y|dkrt||}|j|jjkr8|jj|j}tjd ||j|j|j|jj|jn|jjtjrNd|_ y|jj|Wn<tk r} ztjd |jt| fWYdd} ~ XnX|jjtj|n|d krFt||}|j|jjkr|jj |j}tjd ||j|j|j|jj!|jn|jjtjr$d|_ |jj"||jj"tj|n.|dkrnt#|||d }|rdtjj|tjj|d df|_|j |jtj|} |j|j$j%kr|j$j&|j}|j$j'|j|j(rtjd||j|||j)|ntjd ||j|j|jn|jjtjr,d|_ d| _ |jj*| |r^tjd||j|||j)|n |j$j*|n|dkrDt+||}|j|j,j-kr|j,j.|j}tjd ||j|j|j|j,j/|jn|jjtjrd|_ y|j,j0|Wn<tk r,} ztj1d |jt| fWYdd} ~ XnX|jj0tj|n0|dkrt2||}|j|j3j4kr|j3j5|j}tjd ||j|j|j|j3j6|jn|jjtjrd|_ |j3j7||jj7tj|n|dkrht8||}|j|j9j:kr2|j9j;|j}tjd ||j|j|j|j9j<|jn|jjtjrHd|_ |j9j=||jj>tj|n tj?d|Wqltk r} ztj@d||| WYdd} ~ XqltAk rtj@d||tjBYqlXqlW|rd|j(rd|j|j$j%krX|j$j&|j}tjd||j|j|jy|j$j'|jWntAk rHYnX|jjC|j|j$j*|dS)Nr8Fz.xmlz%s/%sT)combinezLoading %s file '%s'r6z Overloads %s '%s' ('%s/%s')z%s: %s, ignoring for run-time.r7)Z no_check_namerz Combining %s '%s' ('%s/%s')rr;r<zUnknown reader type %szFailed to load %s file '%s': %szFailed to load %s file '%s':z0 Overloading and deactivating %s '%s' ('%s/%s'))Dr{r|isdir startswithrZ ETC_FIREWALLDrbasenamenameZ check_namedefaultsortedlistdirendswithrvrrarr6rxZ get_icmptyperuZremove_icmptypeZ add_icmptyper"rVstrrqrrrr7ryZ get_serviceZremove_serviceZ add_servicerr8rzZget_zoneZ remove_zonecombinedrZadd_zonerr get_ipsets get_ipsetZ remove_ipset add_ipsetr^rr;Z get_helpersZ get_helperZ remove_helperZ add_helperr r< get_policiesZ get_policyZ remove_policyZ add_policyZadd_policy_objectrWrtrnZ exceptionZ forget_zone) r>r|Z reader_typerZ combined_zonerurrZorig_objrtZ config_objrr?r?r@rvs       $             $       zFirewall._loadercCsp|jj|jj|jj|jj|jj|jj|jj|jj|j j|j j|j dS)N) r6cleanupr7r8rr;rr9r:r<r$r=)r>r?r?r@rs          zFirewall.cleanupcCsN|jsB|jr(|j|jj|jd|jrBtjd|jj |j dS)Nrz!Unloading firewall kernel modules) r%rHrrrrIrrar5rr)r>r?r?r@stops    z Firewall.stopc Csd}d}xt|D]\}}|r0|jj|\}}n$|j|dkrDd}n|jj|\}}|dkrn|d7}||7}q|r|jj|d|j|d7<q||jkr|j|d8<|j|dkr|j|=qW||fS)NrrNrT) enumerater5 load_modulerFZ unload_module setdefault) r>Z_modulesenableZ num_failedZ error_msgsimoduleZstatusrr?r?r@handle_moduless(  zFirewall.handle_modulescCs|dkrd|_dS)NrF)r+)r>backendr?r?r@rssz!Firewall._select_firewall_backendcCs4x|jD]}|j|kr |Sq Wttjd|dS)Nz'%s' backend does not exist) all_backendsrr"r!Z UNKNOWN_ERROR)r>rrr?r?r@get_backend_by_names  zFirewall.get_backend_by_namecCs\|jr |jS|dkr |jr |jS|dkr4|jr4|jS|dkrH|jrH|jStt j d|dS)Nr[r\ebz-'%s' is not a valid backend or is unavailable) r+r4r&r-r'r0r(r2r"r! INVALID_IPV)r>ipvr?r?r@get_backend_by_ipvszFirewall.get_backend_by_ipvcCsP|dkr|jr|jS|dkr(|jr(|jS|dkr<|jr<|jSttjd|dS)Nr[r\rz-'%s' is not a valid backend or is unavailable) r&r-r'r0r(r2r"r!r)r>rr?r?r@get_direct_backend_by_ipvsz"Firewall.get_direct_backend_by_ipvcCs<|dkr|jS|dkr|jS|dkr*|jS|dkr8|jSdS)Nr,r/rrF)r&r'r(r+)r>rr?r?r@is_backend_enabledszFirewall.is_backend_enabledcCs8|jr dS|dkr|jS|dkr&|jS|dkr4|jSdS)NTr[r\rF)r+r&r'r()r>rr?r?r@is_ipv_enabledszFirewall.is_ipv_enabledcCsRg}|jr|j|jn6|jr*|j|j|jr<|j|j|jrN|j|j|S)N) r+appendr4r&r-r'r0r(r2)r>backendsr?r?r@enabled_backends s   zFirewall.enabled_backendscCsPg}|jr|j|j|jr(|j|j|jr:|j|j|jrL|j|j|S)N) r&rr-r'r0r(r2r+r4)r>rr?r?r@rs    zFirewall.all_backendsNcCsN|dkrt|}n|}x |jD]}|j||jq W|dkrJ|jddS)NT)rr add_rulesZbuild_default_tablesr)r>rlrrr?r?r@r$s zFirewall.apply_default_tablescCs|dkrt|}n|}x(|jD]}|j|j}|j||q W|jdr~|jd}d|jkr~|jr~|j |j}|j|||jdr|j r|j }|j|||dkr|j ddS)Nr\rawT) rrZbuild_default_rulesrLrrrrUrJZbuild_rpfilter_rulesrQZbuild_rfc3964_ipv4_rulesr)r>rlrrrulesZ ipv6_backendr?r?r@r0s"        zFirewall.apply_default_rulescCs|jr|jj rdSdS)NTF)r+r9Zhas_runtime_configuration)r>r?r?r@may_skip_flush_direct_backendsHsz'Firewall.may_skip_flush_direct_backendscCs`|dkrt|}n|}x2|jD]&}||jkr2q |j}|j||q W|dkr\|jddS)NT)rrrbuild_flush_rulesrr)r>rlrrrr?r?r@flush_direct_backendsNs  zFirewall.flush_direct_backendscCsp|dkrt|}n|}tjd|js4|j|dx$|jD]}|j}|j||q>W|dkrl|jddS)NzFlushing rule set)rlT) rrrarrrrrr)r>rlrrrr?r?r@r]s   zFirewall.flushcCs`|dkrt|}n|}tjd|x&|jD]}|j|}|j||q,W|dkr\|jddS)NzSetting policy to '%s'T)rrrarZbuild_set_policy_rulesrr)r>r<rlrrrr?r?r@ros   zFirewall.set_policycCsB|sdS|j|}|s&ttjd||j|s4dS|j||jS)NrNz'%s' is not a valid backend)rr"r!rrset_rulerL)r> backend_namerulerr?r?r@rs   z Firewall.rulecCs"ttd|}|j|}|s,ttjd||j|s:dS|js\|j s\|dkoX|j j rxt |D]\}}y|j ||j Wqftk r}zjtjtjtj|xFt|d|D]2}y|j |j||j Wqtk rYqXqW|WYdd}~XqfXqfWn|j||j dS)Nz'%s' is not a valid backendr)listrSrr"r!rrrKr_r2r`rrrLrnrra traceback format_excrtreversedZ reverse_ruleZ set_rules)r>rrZ_rulesrrrrr?r?r@rs.     zFirewall.rulescCs|jrttjdS)N)rDr"r!Z PANIC_MODE)r>r?r?r@ check_panicszFirewall.check_paniccCs"|}||jjkrttj||S)N)r<rr"r!ZINVALID_POLICY)r>r<Z_policyr?r?r@ check_policys zFirewall.check_policycCs8|}| s|dkr|j}||jjkr4ttj||S)NrN)get_default_zoner8rzr"r!Z INVALID_ZONE)r>r8_zoner?r?r@r~s  zFirewall.check_zonecCstj|sttj|dS)N)rZcheckInterfacer"r!ZINVALID_INTERFACE)r> interfacer?r?r@check_interfaces zFirewall.check_interfacecCs|jj|dS)N)r7 check_service)r>r7r?r?r@rszFirewall.check_servicecCstj|sttj|dS)N)r check_portr"r!Z INVALID_PORT)r>Zportr?r?r@rs zFirewall.check_portcCs*|sttj|dkr&ttjd|dS)Ntcpudpsctpdccpz''%s' not in {'tcp'|'udp'|'sctp'|'dccp'})rrrr)r"r!ZMISSING_PROTOCOLZINVALID_PROTOCOL)r>Zprotocolr?r?r@ check_tcpudps  zFirewall.check_tcpudpcCstj|sttj|dS)N)rZcheckIPr"r! INVALID_ADDR)r>Zipr?r?r@check_ips zFirewall.check_ipcCsP|dkr tj|sLttj|n,|dkr@tj|sLttj|n ttjddS)Nr[r\z'%s' not in {'ipv4'|'ipv6'})rZ checkIPnMaskr"r!rZ checkIP6nMaskr)r>rsourcer?r?r@ check_addresss  zFirewall.check_addresscCs|jj|dS)N)r6check_icmptype)r>Zicmpr?r?r@rszFirewall.check_icmptypecCs>t|tstd|t|ft|dkr:ttjd|dS)Nz%s is %s, expected intrz#timeout '%d' is not positive number) isinstanceint TypeErrortyper"r! INVALID_VALUE)r>Ztimeoutr?r?r@ check_timeouts   zFirewall.check_timeoutc Cs`|j}|j}|sNi}x&|jjD]}|jj|d||<q W|jj}|j}g}x$|jj D]} |j |jj | q^W|s|j d|j |jd} y|jd|dWn&tk r} z | } WYdd} ~ XnX|r(xL|D]D} |jj| jsx0|jjD]"} | jdkrq| j| jqWqW|s|j}||kr||krRi||<xFt||jD]2\}}|drd||||||<|||=qdWxb|jjD]T}||krx.||D]"}|jj|||||dqW||=n tjd|qWt|d kr6x(t|jD]}tjd |||=qW~x|D]} |jj| jrxx| jD]R}y|jj| j|Wn6tk r}z|jt j!kr|WYdd}~XnXqZWn|jj"| |jj#| jq>W|jj$|t%}|r,x@|jjd gD],}x$t&|D]}|jj|||d q WqW||_|jsD|j d | rVd|_'| nd|_'dS)N interfacesZDROPT)rrr __default__senderzNew zone '%s'.rz(Lost zone '%s', zone interfaces dropped.rN)rrrr)(rDrPr8rz get_settingsr9Zget_runtime_configrrrrrrrrrrnZ query_ipsetrrZ set_destroyritemschange_zone_of_interfacerrVrwkeysZentriesZ add_entryr"rr!ALREADY_ENABLEDrZ apply_ipsetZ set_configrrrC)r>rrDZ flush_allZ_zone_interfacesr8Z_direct_config_old_dzZ _ipset_objs_nameZstart_exceptionrrrZ_new_dzifacesettingsZ interface_identryrZ nm_bus_namerr?r?r@rs                zFirewall.reloadcCs|jS)N)rC)r>r?r?r@ get_stateaszFirewall.get_statecCsZ|jrttjdy|jdWn.tk rN}zttj|WYdd}~XnXd|_dS)Nzpanic mode already enabledZPANICT)rDr"r!rrrnCOMMAND_FAILED)r>rr?r?r@enable_panic_modefszFirewall.enable_panic_modecCsZ|jsttjdy|jdWn.tk rN}zttj|WYdd}~XnXd|_dS)Nzpanic mode is not enabledrF)rDr"r!Z NOT_ENABLEDrrnr)r>rr?r?r@disable_panic_modeqszFirewall.disable_panic_modecCs|jS)N)rD)r>r?r?r@query_panic_mode|szFirewall.query_panic_modecCs|jS)N)rL)r>r?r?r@get_log_deniedszFirewall.get_log_deniedcCsb|tjkr&ttjd|djtjf||jkrR||_|jj d||jj n ttj |dS)Nz'%s', choose from '%s'z','rh) rZLOG_DENIED_VALUESr"r!rjoinrrLr$setwriteZ ALREADY_SET)r>rr?r?r@set_log_denieds   zFirewall.set_log_deniedcCs|jS)N)rE)r>r?r?r@rszFirewall.get_default_zonecCs|j|}||jkr|j}||_|jjd||jj|jj|||jj|}x@t|dj D]\}}|drd|jj d|qdWn t t j |dS)NrcrrrN)r~rEr$rrr8rrrrrr"r!ZZONE_ALREADY_SET)r>r8rrZ_old_dz_settingsrrr?r?r@set_default_zones    zFirewall.set_default_zonecCsH|j}x:|jD].\}}|s(t|tr2|||<q||kr||=qW|S)N)rqrrbool)r>Z permanentZruntimerkeyrr?r?r@'combine_runtime_with_permanent_settingss  z0Firewall.combine_runtime_with_permanent_settingscCsi}i}xt|jt|jBD]}||kr"t||trt||krN||ng}tt|||||<t|t||A|@||<q"t||tst||tr|| r||rd||<q||r|| rd||<q"ttjdj t |||q"W||fS)NTFz Unhandled setting type {} key {}) rrrrrrr"r!ZINVALID_SETTINGformatr)r>Z old_settingsZ new_settingsZ add_settingsZremove_settingsroldr?r?r@get_added_and_removed_settingss   z'Firewall.get_added_and_removed_settings)F)FF)F)N)N)N)N)N)F)4__name__ __module__ __qualname__rArMr=rZrbrrrvrrrrsrrrrrrrrrrrrrrrrrr~rrrrrrrrrrrrrrrrrrrr?r?r?r@rBsh ( ;                s  )A__all__Zos.pathr{rXrqrrZfirewallrrZ firewall.corerrrrr Zfirewall.core.fw_icmptyper Zfirewall.core.fw_servicer Zfirewall.core.fw_zoner Zfirewall.core.fw_directr Zfirewall.core.fw_configrZfirewall.core.fw_policiesrZfirewall.core.fw_ipsetrZfirewall.core.fw_transactionrZfirewall.core.fw_helperrZfirewall.core.fw_policyrZfirewall.core.fw_nmrrZfirewall.core.loggerrZfirewall.core.io.firewalld_confrZfirewall.core.io.directrZfirewall.core.io.servicerZfirewall.core.io.icmptyperZfirewall.core.io.zonerrZfirewall.core.io.ipsetrZfirewall.core.ipsetrZfirewall.core.io.helperrZfirewall.core.io.policyr r!Zfirewall.errorsr"objectrr?r?r?r@sH                            PKpge[|q~q~$__pycache__/fw_config.cpython-36.pycnu[3 g@sdgZddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddl mZmZmZddlmZmZmZddlmZmZmZdd lmZmZmZdd lmZmZm Z dd lm!Z!dd l"m#Z#Gd dde$Z%dS)FirewallConfigN)config)log)IcmpTypeicmptype_readericmptype_writer)Serviceservice_readerservice_writer)Zone zone_reader zone_writer)IPSet ipset_reader ipset_writer)Helper helper_reader helper_writer)Policy policy_reader policy_writer)errors) FirewallErrorc@s$eZdZddZddZddZddZd d Zd d Zd dZ ddZ ddZ ddZ ddZ ddZddZddZddZdd Zd!d"Zd#d$Zd%d&Zd'd(Zd)d*Zd+d,Zd-d.Zd/d0Zd1d2Zd3d4Zd5d6Zd7d8Zd9d:Zd;d<Z d=d>Z!d?d@Z"dAdBZ#dCdDZ$dEdFZ%dGdHZ&dIdJZ'dKdLZ(dMdNZ)dOdPZ*dQdRZ+dSdTZ,dUdVZ-dWdXZ.dYdZZ/d[d\Z0d]d^Z1d_d`Z2dadbZ3dcddZ4dedfZ5dgdhZ6didjZ7dkdlZ8dmdnZ9dodpZ:dqdrZ;dsdtZdydzZ?d{d|Z@d}d~ZAddZBddZCddZDddZEddZFddZGddZHddZIddZJddZKddZLddZMddZNddZOddZPddZQddZRddZSddZTddZUddZVddZWddZXddZYddZZddZ[ddZ\ddZ]ddZ^ddZ_ddZ`ddZaddZbdd„ZcddĄZdddƄZedS)rcCs||_|jdS)N)_fw_FirewallConfig__init_vars)selffwr/usr/lib/python3.6/fw_config.py__init__(szFirewallConfig.__init__cCsHd|j|j|j|j|j|j|j|j|j|j |j |j |j |j |j|jfS)Nz>%s(%r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r, %r)) __class___ipsets _icmptypes _services_zones_helpersZpolicy_objects_builtin_ipsets_builtin_icmptypes_builtin_services_builtin_zones_builtin_helpers_builtin_policy_objects_firewalld_conf _policies_direct)rrrr__repr__,s zFirewallConfig.__repr__cCs^i|_i|_i|_i|_i|_i|_i|_i|_i|_i|_ i|_ i|_ d|_ d|_ d|_dS)N)r!r"r#r$r%_policy_objectsr&r'r(r)r*r+r,r-r.)rrrrZ __init_vars6szFirewallConfig.__init_varscCs4x,t|jjD]}|j|j|j|=qWx,t|jjD]}|j|j|j|=q>Wx,t|jjD]}|j|j|j|=qlWx,t|jjD]}|j|j|j|=qWx,t|jjD]}|j|j|j|=qWx,t|jjD]}|j|j|j|=qWx.t|j jD]}|j |j|j |=q$Wx.t|j jD]}|j |j|j |=qTWx.t|j jD]}|j |j|j |=qWx.t|j jD]}|j |j|j |=qW|j r|j j|` d|_ |jr |jj|`d|_|jr(|jj|`d|_|jdS)N)listr&keyscleanupr!r'r"r(r#r)r$r*r%r,r-r.r)rxrrrr3GsV         zFirewallConfig.cleanupcCs |jjjS)N)rpoliciesZquery_lockdown)rrrrlockdown_enabled~szFirewallConfig.lockdown_enabledcCs|jjj||S)N)rr5 access_check)rkeyvaluerrrr7szFirewallConfig.access_checkcCs ||_dS)N)r,)rconfrrrset_firewalld_confsz!FirewallConfig.set_firewalld_confcCs|jS)N)r,)rrrrget_firewalld_confsz!FirewallConfig.get_firewalld_confcCs(tjjtjs|jjn |jjdS)N)ospathexistsrZFIREWALLD_CONFr,clearread)rrrrupdate_firewalld_confs z$FirewallConfig.update_firewalld_confcCs ||_dS)N)r-)rr5rrr set_policiesszFirewallConfig.set_policiescCs|jS)N)r-)rrrr get_policiesszFirewallConfig.get_policiescCs,tjjtjs|jjjn |jjjdS)N) r=r>r?rZLOCKDOWN_WHITELISTr-Zlockdown_whitelistr3rA)rrrrupdate_lockdown_whitelistsz(FirewallConfig.update_lockdown_whitelistcCs ||_dS)N)r.)rZdirectrrr set_directszFirewallConfig.set_directcCs|jS)N)r.)rrrr get_directszFirewallConfig.get_directcCs(tjjtjs|jjn |jjdS)N)r=r>r?rZFIREWALLD_DIRECTr.r3rA)rrrr update_directs zFirewallConfig.update_directcCs$ttt|jjt|jjS)N)sortedsetr1r!r2r&)rrrr get_ipsetsszFirewallConfig.get_ipsetscCs$|jr||j|j<n ||j|j<dS)N)builtinr&namer!)robjrrr add_ipsetszFirewallConfig.add_ipsetcCs8||jkr|j|S||jkr(|j|Sttj|dS)N)r!r&rr INVALID_IPSET)rrMrrr get_ipsets     zFirewallConfig.get_ipsetcCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._ipsets[%s] != objz'%s' not a built-in ipset)rMr!rr NO_DEFAULTSr& _remove_ipset)rrNrrrload_ipset_defaultss    z"FirewallConfig.load_ipset_defaultscCs|jS)N) export_config)rrNrrrget_ipset_configszFirewallConfig.get_ipset_configcCsj|jrPtj|}|j|tj|_d|_|j|jkr:d|_|j|t||S|j|t||SdS)NF) rLcopy import_configrETC_FIREWALLD_IPSETSr>defaultrOr)rrNr:r4rrrset_ipset_configs     zFirewallConfig.set_ipset_configcCsx||jks||jkr$ttjd|t}|j||j|||_d||_ t j |_ d|_ d|_t||j||S)Nznew_ipset(): '%s'z%s.xmlFT)r!r&rr NAME_CONFLICTr check_namerXrMfilenamerrYr>rLrZrrO)rrMr:r4rrr new_ipsets     zFirewallConfig.new_ipsetcCstjj|}tjj|}tjj|s|tjkrx|jjD]D}|j|}|j |kr:|j|=|j |j krvd|j |j fSd|fSq:WnHxF|j jD]8}|j |}|j |kr|j |=|j |jkrd|fSdSqWdSt j d|yt||}Wn0tk r}zt jd||dSd}~XnX|j |j krJ|j |jkrJ|j|d|fS|tjkr|j |jkr|j|j j|_||j|j <d|fS|j |j kr|j |j =||j |j <|j |jkrd|fSd Sd S) NupdateremovezLoading ipset file '%s'z"Failed to load ipset file '%s': %snew)NN)NN)NN)NN)NN)r=r>basenamedirnamer?rrYr!r2r^rMr&rdebug1r ExceptionerrorrOrZ)rrMr^r>r4rNmsgrrrupdate_ipset_from_pathsP                z%FirewallConfig.update_ipset_from_pathcCs|j|jkrttj|j|jtjkr>ttjd|jtjfd|j|jf}yt j |d|Wn:t k r}zt j d||tj|WYdd}~XnX|j|j=dS)Nz '%s' != '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr!rrrPr>rrYINVALID_DIRECTORYshutilmoverfrrgr=ra)rrNrMrhrrrrS8s   zFirewallConfig._remove_ipsetcCs$|js|j r ttjd|jdS)Nz'%s' is built-in ipset)rLrZrrZ BUILTIN_IPSETrM)rrNrrrcheck_builtin_ipsetIsz"FirewallConfig.check_builtin_ipsetcCs|j||j|dS)N)rmrS)rrNrrr remove_ipsetNs zFirewallConfig.remove_ipsetcCs$|j||j||}|j||S)N)rm _copy_ipsetrS)rrNrMr_rrr rename_ipsetRs   zFirewallConfig.rename_ipsetcCs|j||jS)N)r_rU)rrNrMrrrroXszFirewallConfig._copy_ipsetcCs$ttt|jjt|jjS)N)rIrJr1r"r2r')rrrr get_icmptypes]szFirewallConfig.get_icmptypescCs$|jr||j|j<n ||j|j<dS)N)rLr'rMr")rrNrrr add_icmptypeaszFirewallConfig.add_icmptypecCs8||jkr|j|S||jkr(|j|Sttj|dS)N)r"r'rrINVALID_ICMPTYPE)rrMrrr get_icmptypegs     zFirewallConfig.get_icmptypecCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._icmptypes[%s] != objz'%s' not a built-in icmptype)rMr"rrrRr'_remove_icmptype)rrNrrrload_icmptype_defaultsns    z%FirewallConfig.load_icmptype_defaultscCs|jS)N)rU)rrNrrrget_icmptype_configzsz"FirewallConfig.get_icmptype_configcCsj|jrPtj|}|j|tj|_d|_|j|jkr:d|_|j|t||S|j|t||SdS)NF) rLrWrXrETC_FIREWALLD_ICMPTYPESr>rZrrr)rrNr:r4rrrset_icmptype_config}s     z"FirewallConfig.set_icmptype_configcCsx||jks||jkr$ttjd|t}|j||j|||_d||_ t j |_ d|_ d|_t||j||S)Nznew_icmptype(): '%s'z%s.xmlFT)r"r'rrr\rr]rXrMr^rrxr>rLrZrrr)rrMr:r4rrr new_icmptypes     zFirewallConfig.new_icmptypecCstjj|}tjj|}tjj|s|tjkrx|jjD]D}|j|}|j |kr:|j|=|j |j krvd|j |j fSd|fSq:WnHxF|j jD]8}|j |}|j |kr|j |=|j |jkrd|fSdSqWdSt j d|yt||}Wn0tk r}zt jd||dSd}~XnX|j |j krJ|j |jkrJ|j|d|fS|tjkr|j |jkr|j|j j|_||j|j <d|fS|j |j kr|j |j =||j |j <|j |jkrd|fSd Sd S) Nr`razLoading icmptype file '%s'z%Failed to load icmptype file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rrxr"r2r^rMr'rrerrfrgrrrZ)rrMr^r>r4rNrhrrrupdate_icmptype_from_pathsP                z(FirewallConfig.update_icmptype_from_pathcCs|j|jkrttj|j|jtjkr>ttjd|jtjfd|j|jf}yt j |d|Wn:t k r}zt j d||tj|WYdd}~XnX|j|j=dS)Nz '%s' != '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr"rrrsr>rrxrjrkrlrfrrgr=ra)rrNrMrhrrrrus  zFirewallConfig._remove_icmptypecCs$|js|j r ttjd|jdS)Nz'%s' is built-in icmp type)rLrZrrZBUILTIN_ICMPTYPErM)rrNrrrcheck_builtin_icmptypesz%FirewallConfig.check_builtin_icmptypecCs|j||j|dS)N)r|ru)rrNrrrremove_icmptypes zFirewallConfig.remove_icmptypecCs$|j||j||}|j||S)N)r|_copy_icmptyperu)rrNrMrzrrrrename_icmptypes   zFirewallConfig.rename_icmptypecCs|j||jS)N)rzrU)rrNrMrrrr~szFirewallConfig._copy_icmptypecCs$ttt|jjt|jjS)N)rIrJr1r#r2r()rrrr get_services szFirewallConfig.get_servicescCs$|jr||j|j<n ||j|j<dS)N)rLr(rMr#)rrNrrr add_serviceszFirewallConfig.add_servicecCs<||jkr|j|S||jkr(|j|Sttjd|dS)Nzget_service(): '%s')r#r(rrINVALID_SERVICE)rrMrrr get_services     zFirewallConfig.get_servicecCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._services[%s] != objz'%s' not a built-in service)rMr#rrrRr(_remove_service)rrNrrrload_service_defaultss    z$FirewallConfig.load_service_defaultscCsr|j}g}x\tdD]P}|j|d|krN|jtjt||j|dq|j||j|dqWt|S)Nr)export_config_dictrangeIMPORT_EXPORT_STRUCTUREappendrWdeepcopygetattrtuple)rrN conf_dict conf_listirrrget_service_config's"z!FirewallConfig.get_service_configcCs|jS)N)r)rrNrrrget_service_config_dict3sz&FirewallConfig.get_service_config_dictcCsi}x&t|D]\}}|||j|d<qW|jr|tj|}|j|tj|_d|_|j|jkrfd|_|j |t ||S|j|t ||SdS)NrF) enumeraterrLrWimport_config_dictrETC_FIREWALLD_SERVICESr>rZrr )rrNr:rrr9r4rrrset_service_config6s      z!FirewallConfig.set_service_configcCsj|jrPtj|}|j|tj|_d|_|j|jkr:d|_|j|t||S|j|t||SdS)NF) rLrWrrrr>rZrr )rrNr:r4rrrset_service_config_dictJs     z&FirewallConfig.set_service_config_dictcCs||jks||jkr$ttjd|i}x&t|D]\}}||tj|d<q2Wt}|j||j |||_ d||_ t j |_d|_d|_t||j||S)Nznew_service(): '%s'rz%s.xmlFT)r#r(rrr\rrrr]rrMr^rrr>rLrZr r)rrMr:rrr9r4rrr new_serviceZs"     zFirewallConfig.new_servicecCsx||jks||jkr$ttjd|t}|j||j|||_d||_ t j |_ d|_ d|_t||j||S)Nznew_service(): '%s'z%s.xmlFT)r#r(rrr\rr]rrMr^rrr>rLrZr r)rrMr:r4rrrnew_service_dictqs     zFirewallConfig.new_service_dictcCstjj|}tjj|}tjj|s|tjkrx|jjD]D}|j|}|j |kr:|j|=|j |j krvd|j |j fSd|fSq:WnHxF|j jD]8}|j |}|j |kr|j |=|j |jkrd|fSdSqWdSt j d|yt||}Wn0tk r}zt jd||dSd}~XnX|j |j krJ|j |jkrJ|j|d|fS|tjkr|j |jkr|j|j j|_||j|j <d|fS|j |j kr|j |j =||j |j <|j |jkrd|fSd Sd S) Nr`razLoading service file '%s'z$Failed to load service file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rrr#r2r^rMr(rrer rfrgrrZ)rrMr^r>r4rNrhrrrupdate_service_from_pathsP                z'FirewallConfig.update_service_from_pathcCs|j|jkrttj|j|jtjkr>ttjd|jtjfd|j|jf}yt j |d|Wn:t k r}zt j d||tj|WYdd}~XnX|j|j=dS)Nz '%s' != '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr#rrrr>rrrjrkrlrfrrgr=ra)rrNrMrhrrrrs  zFirewallConfig._remove_servicecCs$|js|j r ttjd|jdS)Nz'%s' is built-in service)rLrZrrZBUILTIN_SERVICErM)rrNrrrcheck_builtin_servicesz$FirewallConfig.check_builtin_servicecCs|j||j|dS)N)rr)rrNrrrremove_services zFirewallConfig.remove_servicecCs$|j||j||}|j||S)N)r _copy_servicer)rrNrMrrrrrename_services   zFirewallConfig.rename_servicecCs|j||jS)N)rr)rrNrMrrrrszFirewallConfig._copy_servicecCs$ttt|jjt|jjS)N)rIrJr1r$r2r))rrrr get_zonesszFirewallConfig.get_zonescCs$|jr||j|j<n ||j|j<dS)N)rLr)rMr$)rrNrrradd_zoneszFirewallConfig.add_zonecCs(||jkr|j|=||jkr$|j|=dS)N)r)r$)rrMrrr forget_zones  zFirewallConfig.forget_zonecCs<||jkr|j|S||jkr(|j|Sttjd|dS)Nzget_zone(): %s)r$r)rr INVALID_ZONE)rrMrrrget_zones     zFirewallConfig.get_zonecCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._zones[%s] != objz'%s' not a built-in zone)rMr$rrrRr) _remove_zone)rrNrrrload_zone_defaultss    z!FirewallConfig.load_zone_defaultscCsr|j}g}x\tdD]P}|j|d|krN|jtjt||j|dq|j||j|dqWt|S)Nr)rrrrrWrrr)rrNrrrrrrget_zone_configs"zFirewallConfig.get_zone_configcCs|jS)N)r)rrNrrrget_zone_config_dictsz#FirewallConfig.get_zone_config_dictcCsi}x&t|D]\}}|||j|d<qW|jrtj|}||_|j|tj|_d|_|j|jkrld|_ |j |t ||S||_|j|t ||SdS)NrF) rrrLrW fw_configrrETC_FIREWALLD_ZONESr>rZrr )rrNr:rrr9r4rrrset_zone_config s$     zFirewallConfig.set_zone_configcCsv|jrVtj|}||_|j|tj|_d|_|j|jkr@d|_|j|t ||S||_|j|t ||SdS)NF) rLrWrrrrr>rZrr )rrNr:r4rrrset_zone_config_dict6s     z#FirewallConfig.set_zone_config_dictcCs||jks||jkr$ttjd|i}x&t|D]\}}||tj|d<q2Wt}||_|j ||j |||_ d||_ t j|_d|_d|_t||j||S)Nznew_zone(): '%s'rz%s.xmlFT)r$r)rrr\rr rrr]rrMr^rrr>rLrZr r)rrMr:rrr9r4rrrnew_zoneHs"    zFirewallConfig.new_zonecCs~||jks||jkr$ttjd|t}||_|j||j|||_ d||_ t j |_ d|_d|_t||j||S)Nznew_zone(): '%s'z%s.xmlFT)r$r)rrr\r rr]rrMr^rrr>rLrZr r)rrMr:r4rrr new_zone_dict_s    zFirewallConfig.new_zone_dictcCstjj|}tjj|}tjj|s|jtjrx|jj D]D}|j|}|j |kr<|j|=|j |j krxd|j |j fSd|fSqrcrdr? startswithrrr$r2r^rMr)rrer rfrgrlenrrZ)rrMr^r>r4rNrhrrrupdate_zone_from_pathrsZ                z$FirewallConfig.update_zone_from_pathcCs|j|jkrttj|j|jjtjs@ttj d|jtjfd|j|jf}yt j |d|Wn:t k r}zt jd||tj|WYdd}~XnX|j|j=dS)Nz'%s' doesn't start with '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr$rrrr>rrrrjrkrlrfrrgr=ra)rrNrMrhrrrrs zFirewallConfig._remove_zonecCs$|js|j r ttjd|jdS)Nz'%s' is built-in zone)rLrZrrZ BUILTIN_ZONErM)rrNrrrcheck_builtin_zonesz!FirewallConfig.check_builtin_zonecCs|j||j|dS)N)rr)rrNrrr remove_zones zFirewallConfig.remove_zonec CsN|j||j}|j|y|j||}Wn|j|j|YnX|S)N)rrrrrM)rrNrMZobj_confrrrr rename_zones  zFirewallConfig.rename_zonecCs$ttt|jjt|jjS)N)rIrJr1r0r2r+)rrrrget_policy_objectssz!FirewallConfig.get_policy_objectscCs$|jr||j|j<n ||j|j<dS)N)rLr+rMr0)rrNrrradd_policy_objectsz FirewallConfig.add_policy_objectcCs<||jkr|j|S||jkr(|j|Sttjd|dS)Nzget_policy_object(): %s)r0r+rrINVALID_POLICY)rrMrrrget_policy_objects     z FirewallConfig.get_policy_objectcCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._policy_objects[%s] != objz'%s' not a built-in policy)rMr0rrrRr+_remove_policy_object)rrNrrrload_policy_object_defaultss    z*FirewallConfig.load_policy_object_defaultscCs|jS)N)r)rrNrrrget_policy_object_config_dictsz,FirewallConfig.get_policy_object_config_dictcCsv|jrVtj|}||_|j|tj|_d|_|j|jkr@d|_|j|t ||S||_|j|t ||SdS)NF) rLrWrrrETC_FIREWALLD_POLICIESr>rZrr)rrNr:r4rrrset_policy_object_config_dicts     z,FirewallConfig.set_policy_object_config_dictcCs~||jks||jkr$ttjd|t}||_|j||j|||_ d||_ t j |_ d|_d|_t||j||S)Nznew_policy_object(): '%s'z%s.xmlFT)r0r+rrr\rrr]rrMr^rrr>rLrZrr)rrMr:r4rrrnew_policy_object_dicts    z%FirewallConfig.new_policy_object_dictcCstjj|}tjj|}tjj|s|jtjrx|jj D]D}|j|}|j |kr<|j|=|j |j krxd|j |j fSd|fSqrcrdr?rrrr0r2r^rMr+rrerrfrgrrrrZ)rrMr^r>r4rNrhrrrupdate_policy_object_from_path,sZ                z-FirewallConfig.update_policy_object_from_pathcCs|j|jkrttj|j|jjtjs@ttj d|jtjfd|j|jf}yt j |d|Wn:t k r}zt jd||tj|WYdd}~XnX|j|j=dS)Nz'%s' doesn't start with '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr0rrrr>rrrrjrkrlrfrrgr=ra)rrNrMrhrrrrys z$FirewallConfig._remove_policy_objectcCs$|js|j r ttjd|jdS)Nz'%s' is built-in policy)rLrZrrZBUILTIN_POLICYrM)rrNrrrcheck_builtin_policy_objectsz*FirewallConfig.check_builtin_policy_objectcCs|j||j|dS)N)rr)rrNrrrremove_policy_objects z#FirewallConfig.remove_policy_objectcCs$|j||j||}|j||S)N)r_copy_policy_objectr)rrNrMZnew_policy_objectrrrrename_policy_objects   z#FirewallConfig.rename_policy_objectcCs|j||jS)N)rr)rrNrMrrrrsz"FirewallConfig._copy_policy_objectcCs$ttt|jjt|jjS)N)rIrJr1r%r2r*)rrrr get_helpersszFirewallConfig.get_helperscCs$|jr||j|j<n ||j|j<dS)N)rLr*rMr%)rrNrrr add_helperszFirewallConfig.add_helpercCs8||jkr|j|S||jkr(|j|Sttj|dS)N)r%r*rrINVALID_HELPER)rrMrrr get_helpers     zFirewallConfig.get_helpercCst|j|jkrttj|jnB|j|j|kr@ttjd|jn|j|jkr^ttjd|j|j||j|jS)Nzself._helpers[%s] != objz'%s' not a built-in helper)rMr%rrrRr*_remove_helper)rrNrrrload_helper_defaultss    z#FirewallConfig.load_helper_defaultscCs|jS)N)rU)rrNrrrget_helper_configsz FirewallConfig.get_helper_configcCsj|jrPtj|}|j|tj|_d|_|j|jkr:d|_|j|t||S|j|t||SdS)NF) rLrWrXrETC_FIREWALLD_HELPERSr>rZrr)rrNr:r4rrrset_helper_configs     z FirewallConfig.set_helper_configcCsx||jks||jkr$ttjd|t}|j||j|||_d||_ t j |_ d|_ d|_t||j||S)Nznew_helper(): '%s'z%s.xmlFT)r%r*rrr\rr]rXrMr^rrr>rLrZrr)rrMr:r4rrr new_helpers     zFirewallConfig.new_helpercCstjj|}tjj|}tjj|s|tjkrx|jjD]D}|j|}|j |kr:|j|=|j |j krvd|j |j fSd|fSq:WnHxF|j jD]8}|j |}|j |kr|j |=|j |jkrd|fSdSqWdSt j d|yt||}Wn0tk r}zt jd||dSd}~XnX|j |j krJ|j |jkrJ|j|d|fS|tjkr|j |jkr|j|j j|_||j|j <d|fS|j |j kr|j |j =||j |j <|j |jkrd|fSd Sd S) Nr`razLoading helper file '%s'z#Failed to load helper file '%s': %srb)NN)NN)NN)NN)NN)r=r>rcrdr?rrr%r2r^rMr*rrerrfrgrrZ)rrMr^r>r4rNrhrrrupdate_helper_from_pathsP                z&FirewallConfig.update_helper_from_pathcCs|j|jkrttj|j|jtjkr>ttjd|jtjfd|j|jf}yt j |d|Wn:t k r}zt j d||tj|WYdd}~XnX|j|j=dS)Nz '%s' != '%s'z %s/%s.xmlz%s.oldzBackup of file '%s' failed: %s)rMr%rrrr>rrrjrkrlrfrrgr=ra)rrNrMrhrrrr&s   zFirewallConfig._remove_helpercCs$|js|j r ttjd|jdS)Nz'%s' is built-in helper)rLrZrrZBUILTIN_HELPERrM)rrNrrrcheck_builtin_helper7sz#FirewallConfig.check_builtin_helpercCs|j||j|dS)N)rr)rrNrrr remove_helper<s zFirewallConfig.remove_helpercCs$|j||j||}|j||S)N)r _copy_helperr)rrNrMrrrr rename_helper@s   zFirewallConfig.rename_helpercCs|j||jS)N)rrU)rrNrMrrrrFszFirewallConfig._copy_helperN)f__name__ __module__ __qualname__rr/rr3r6r7r;r<rBrCrDrErFrGrHrKrOrQrTrVr[r_rirSrmrnrprorqrrrtrvrwryrzr{rur|r}rr~rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr's 7 E E  E  M M E)&__all__rWr=Zos.pathrkZfirewallrZfirewall.core.loggerrZfirewall.core.io.icmptyperrrZfirewall.core.io.servicerr r Zfirewall.core.io.zoner r r Zfirewall.core.io.ipsetrrrZfirewall.core.io.helperrrrZfirewall.core.io.policyrrrrZfirewall.errorsrobjectrrrrrs    PKpge[QQ__pycache__/rich.cpython-36.pycnu[3 g8@sdddddddddd d d d d ddddgZddlmZddlmZddlmZddlmZddlm Z Gddde Z Gddde Z Gddde Z Gddde ZGdddeZGddde ZGddde ZGddde ZGd dde ZGd!d d e ZGd"d d e ZGd#d d e ZGd$d d e ZGd%d d e ZGd&ddeZGd'dde Zd(d)d/d1d+ZGd,dde ZGd-dde Zd.S)2 Rich_SourceRich_Destination Rich_Service Rich_Port Rich_ProtocolRich_MasqueradeRich_IcmpBlock Rich_IcmpTypeRich_SourcePortRich_ForwardPortRich_Log Rich_Audit Rich_Accept Rich_Reject Rich_Drop Rich_Mark Rich_Limit Rich_Rule) functions)check_ipset_name) REJECT_TYPES)errors) FirewallErrorc@seZdZdddZddZdS)rFcCs||_|jdkrd|_||_|jdks0|jdkr8d|_n|jdk rN|jj|_||_|jdkrdd|_||_|jdkr|jdkr|jdkrttjddS)Nzno address, mac and ipset)addrmacupperipsetinvertrr INVALID_RULE)selfrrrrr!/usr/lib/python3.6/rich.py__init__$s    zRich_Source.__init__cCsjd|jr dnd}|jdk r*|d|jS|jdk rB|d|jS|jdk rZ|d|jSttjddS)Nz source%s z NOTrz address="%s"zmac="%s"z ipset="%s"zno address, mac and ipset)rrrrrrr)r retr!r!r"__str__5s   zRich_Source.__str__N)F)__name__ __module__ __qualname__r#r%r!r!r!r"r#s c@seZdZdddZddZdS)rFcCsV||_|jdkrd|_||_|jdkr,d|_||_|jdkrR|jdkrRttjddS)Nrzno address and ipset)rrrrrr)r rrrr!r!r"r#Bs  zRich_Destination.__init__cCsRd|jr dnd}|jdk r*|d|jS|jdk rB|d|jSttjddS)Nzdestination%s z NOTrz address="%s"z ipset="%s"zno address and ipset)rrrrrr)r r$r!r!r"r%Ns  zRich_Destination.__str__N)F)r&r'r(r#r%r!r!r!r"rAs c@seZdZddZddZdS)rcCs ||_dS)N)name)r r)r!r!r"r#YszRich_Service.__init__cCs d|jS)Nzservice name="%s")r))r r!r!r"r%\szRich_Service.__str__N)r&r'r(r#r%r!r!r!r"rXsc@seZdZddZddZdS)rcCs||_||_dS)N)portprotocol)r r*r+r!r!r"r#`szRich_Port.__init__cCsd|j|jfS)Nzport port="%s" protocol="%s")r*r+)r r!r!r"r%dszRich_Port.__str__N)r&r'r(r#r%r!r!r!r"r_sc@seZdZddZdS)r cCsd|j|jfS)Nz#source-port port="%s" protocol="%s")r*r+)r r!r!r"r%hszRich_SourcePort.__str__N)r&r'r(r%r!r!r!r"r gsc@seZdZddZddZdS)rcCs ||_dS)N)value)r r,r!r!r"r#mszRich_Protocol.__init__cCs d|jS)Nzprotocol value="%s")r,)r r!r!r"r%pszRich_Protocol.__str__N)r&r'r(r#r%r!r!r!r"rlsc@seZdZddZddZdS)rcCsdS)Nr!)r r!r!r"r#tszRich_Masquerade.__init__cCsdS)N masquerader!)r r!r!r"r%wszRich_Masquerade.__str__N)r&r'r(r#r%r!r!r!r"rssc@seZdZddZddZdS)rcCs ||_dS)N)r))r r)r!r!r"r#{szRich_IcmpBlock.__init__cCs d|jS)Nzicmp-block name="%s")r))r r!r!r"r%~szRich_IcmpBlock.__str__N)r&r'r(r#r%r!r!r!r"rzsc@seZdZddZddZdS)rcCs ||_dS)N)r))r r)r!r!r"r#szRich_IcmpType.__init__cCs d|jS)Nzicmp-type name="%s")r))r r!r!r"r%szRich_IcmpType.__str__N)r&r'r(r#r%r!r!r!r"rsc@seZdZddZddZdS)r cCs<||_||_||_||_|jdkr(d|_|jdkr8d|_dS)Nr)r*r+to_port to_address)r r*r+r.r/r!r!r"r#s  zRich_ForwardPort.__init__cCs<d|j|j|jdkrd|jnd|jdkr4d|jndfS)Nz(forward-port port="%s" protocol="%s"%s%srz to-port="%s"z to-addr="%s")r*r+r.r/)r r!r!r"r%szRich_ForwardPort.__str__N)r&r'r(r#r%r!r!r!r"r s c@seZdZdddZddZdS)r NcCs||_||_||_dS)N)prefixlevellimit)r r0r1r2r!r!r"r#szRich_Log.__init__cCs>d|jrd|jnd|jr$d|jnd|jr6d|jndfS)Nz log%s%s%sz prefix="%s"rz level="%s"z %s)r0r1r2)r r!r!r"r%szRich_Log.__str__)NNN)r&r'r(r#r%r!r!r!r"r s c@seZdZdddZddZdS)r NcCs ||_dS)N)r2)r r2r!r!r"r#szRich_Audit.__init__cCsd|jrd|jndS)Nzaudit%sz %sr)r2)r r!r!r"r%szRich_Audit.__str__)N)r&r'r(r#r%r!r!r!r"r s c@seZdZdddZddZdS)r NcCs ||_dS)N)r2)r r2r!r!r"r#szRich_Accept.__init__cCsd|jrd|jndS)Nzaccept%sz %sr)r2)r r!r!r"r%szRich_Accept.__str__)N)r&r'r(r#r%r!r!r!r"r s c@s&eZdZdddZddZddZdS) rNcCs||_||_dS)N)typer2)r Z_typer2r!r!r"r#szRich_Reject.__init__cCs,d|jrd|jnd|jr$d|jndfS)Nz reject%s%sz type="%s"rz %s)r3r2)r r!r!r"r%szRich_Reject.__str__cCsT|jrP|sttjd|dkrP|jt|krPdjt|}ttjd|j|fdS)Nz9When using reject type you must specify also rule family.ipv4ipv6z, z%Wrong reject type %s. Use one of: %s.)r4r5)r3rrrrjoin)r familyZ valid_typesr!r!r"checks zRich_Reject.check)NN)r&r'r(r#r%r8r!r!r!r"rs c@seZdZddZdS)rcCsd|jrd|jndS)Nzdrop%sz %sr)r2)r r!r!r"r%szRich_Drop.__str__N)r&r'r(r%r!r!r!r"rsc@s&eZdZdddZddZddZdS) rNcCs||_||_dS)N)setr2)r Z_setr2r!r!r"r#szRich_Mark.__init__cCsd|j|jrd|jndfS)Nz mark set=%s%sz %sr)r9r2)r r!r!r"r%szRich_Mark.__str__cCs|jdk r|j}n ttjdd|krv|jd}t|dkrHttj|tj|d shtj|d rttj|ntj|sttj|dS)Nz no value set/r)r9rrZ INVALID_MARKsplitlenrZ checkUINT32)r xsplitsr!r!r"r8s      zRich_Mark.check)N)r&r'r(r#r%r8r!r!r!r"rs r<<)smhdc@seZdZdddZddZeddZejddZed d Zejd d Ze d d Z ddZ e ddZ ddZ ddZdS)rNcCs||_||_dS)N)r,burst)r r,rGr!r!r"r#szRich_Limit.__init__cCs|j|jdS)N) value_parse burst_parse)r r!r!r"r8szRich_Limit.checkcCs|jS)N)_value)r r!r!r"r,szRich_Limit.valuec Csf|dkrd|_dSy|j|\}}Wntk r<|}YnX|d|}t|dd|krb||_dS)Nr:rJ)rJ _value_parsergetattr)r r,ratedurationvr!r!r"r,s cCs|jS)N)_burst)r r!r!r"rG szRich_Limit.burstc Cs\|dkrd|_dSy|j|}Wntk r8|}Yn Xt|}t|dd|krX||_dS)NrP)rP _burst_parserstrrL)r rGbr!r!r"rGs c Csd}d|kr|jd}| s(t|dkr4ttj||\}}y t|}Wnttj|YnX|dkrv|dd}|dks|dkrttj|d t||d krttjd|f|dkr|d krttjd|f||fS)Nr:r;secondminutehourdayr<rCrDrErFi'rz %s too fastz %s too slow)rTrUrVrW)rCrDrErF)r=r>rr INVALID_LIMITintDURATION_TO_MULT)r,r@rMrNr!r!r"rKs&     zRich_Limit._value_parsecCs |j|jS)N)rKrJ)r r!r!r"rH:szRich_Limit.value_parsec CsR|dkr dSy t|}Wnttj|YnX|dksB|dkrNttj||S)Nr<i)rYrrrX)rGrSr!r!r"rQ=s  zRich_Limit._burst_parsecCs |j|jS)N)rQrP)r r!r!r"rIKszRich_Limit.burst_parsecCs,d|jd}|jdk r(|d|j7}|S)Nz limit value=""z burst=)rJrP)r rCr!r!r"r%Ns zRich_Limit.__str__)N)r&r'r(r#r8propertyr,setterrG staticmethodrKrHrQrIr%r!r!r!r"rs     c@s>eZdZdZdZdddZddZd d Zd d Zd dZ dS)riiNrcCsV|dk rt||_nd|_||_d|_d|_d|_d|_d|_d|_|rR|j |dS)N) rRr7prioritysource destinationelementlogauditaction_import_from_string)r r7rule_strr_r!r!r"r#Xs zRich_Rule.__init__cCsg}x|tj|D]n}d|krp|jd}t|dksF|d sF|d rVttjd||j|d|ddq|jd|iqW|jddi|S) z Lexical analysis =r;rr<zinternal error in _lexer(): %s) attr_name attr_valuerbEOL)rZ splitArgsr=r>rrrappend)r rgtokensrattrr!r!r"_lexeris   zRich_Rule._lexerc Cs|sttjdtj|}d|_d|_d|_d|_d|_ d|_ d|_ d|_ |j |}|rv|djddkrvttjdi}g}d}x`||jddko|dgks||jd}||jd}||jd}|r|dHkrttjd|n|dIkr|dkr|jrttjd+n|dkr<|jr|d <nBt|jd |jd |jd |jd d?|_|j|j|d2}n| dkr,|dOkr|||<nN|dPkrd>|d <n:t|jd |jd |jd d?|_|j|j|d2}n| dkrd|dkrTt||_ |jn ttjd@nv| dkr|dkrt||_ |jn ttjdAn>| dkr|dQkr|||<n0t|jd|jd|_ |j|j|d2}n| dkr&|dkrt||_ |jn ttjdBn| dkr^|dkrNt||_ |jn ttjdCn|| dkrt|_ |j|j|d2}nN| d kr|dRkr|||<n@t|jd|jd|jd|jd|_ |j|j|d2}n| d!kr@|dSkr |||<n0t|jd|jd|_ |j|j|d2}n| d"kr|dTkr^|||<nN|d(krt|jd(n8t |jd|jd|jd(|_ |j|j|d2}n*| d#kr|d(kr|jd(n(t!|jd(|_ |j|j|d2}n| d$krH|d(kr|jd(n(t"|jd(|_ |j|j|d2}n| d%kr|d(krh|jd(n(t#|jd(|_ |j|j|d2}nF| d&kr|dkr|||<nF|d(kr|jd(n0t$|jd|jd(|_ |j|j|d2}n| d'kr`|dkr|||<nF|d(kr.|jd(n0t%|jd|jd(|_ |j|j|d2}nz| d(kr|dUkr||dD|<nVdE|krttjdFt&|dE|jdG|d(<|jdEd|jdGd|j|d2}|d2}qW|j'dS)VNz empty rulerrbrkrulerirjr_r7addressrrrr,r*r+to-portto-addrr)r0r1r3r9rGzbad attribute '%s'r`raservice icmp-block icmp-typer- forward-port source-portrcrdacceptdroprejectmarkr2notNOTzmore than one 'source' elementz#more than one 'destination' elementzFmore than one element. There cannot be both '%s' and '%s' in one rule.zmore than one 'log' elementzmore than one 'audit' elementzOmore than one 'action' element. There cannot be both '%s' and '%s' in one rule.zunknown element %sr<rz0'family' outside of rule. Use 'rule family=...'.z4'priority' outside of rule. Use 'rule priority=...'.z:'%s' outside of any element. Use 'rule %s= ...'.z,'%s' outside of rule. Use 'rule ... %s ...'.r4r5zH'family' attribute cannot have '%s' value. Use 'ipv4' or 'ipv6' instead.z(invalid 'priority' attribute value '%s'.zdwrong 'protocol' usage. Use either 'rule protocol value=...' or 'rule [forward-]port protocol=...'.zDattribute '%s' outside of any element. Use 'rule %s= ...'.TFzinvalid 'protocol' elementzinvalid 'service' elementzinvalid 'icmp-block' elementzinvalid 'icmp-type' elementzlimit.z limit.valuezinvalid 'limit' elementz limit.burst)r_r7rrrrrr,r*r+rsrtr)r0r1r3r9rG)rqr`rar+rur*rvrwr-rxryrcrdrzr{r|r}r2r~rrk)r+rur*rvrwr-rxry)rzr{r|r})r4r5)rrrrr)r~r)rrrr)r~r)r*r+)r*r+rsrt)r*r+)r0r1)r,rG)(rrrrZstripNonPrintableCharactersr_r7r`rarbrcrdrerpgetr>rlrY ValueErrorINVALID_PRIORITYrpopclearrrrrrrrr r r r r rrrrr8) r rgrmZattrsZ in_elementsindexrbrirjZ in_elementZerr_msgr!r!r"rfzs    ""               *      "                          (                                            zRich_Rule._import_from_stringc Cs`|jdk r"|jd kr"ttj|j|jdkrn|jdk rB|jjdk sL|jdk rVttjt|j t krnttj|j |j ks|j |j krttjd|j |j f|j dko|jdks|jdk o|j dkr |jdkrttjd|jdko|jdko|j dkr ttjdt|j tt tgkrP|jdkrP|jdkrP|jdkrPttjd|jdk rj|jjdk r|jdkrttj|jjdk rttjd|jjdk rttjd tj|j|jjsjttjt|jjn|jjdk r,|jjdk rttjd tj|jjsjttjt|jjn>|jjdk r^t|jjsjttjt|jjn ttjd |jdk r|jjdk r|jdkrttj|jjdk rttjd tj|j|jjsttjt|jjn>|jjdk rt|jjsttjt|jjn ttjd t|j t krd|j j!dksLt"|j j!d kr`ttj#t|j j!nt|j t$krtj%|j j&sttj'|j j&|j j(d!kr`ttj)|j j(nt|j t*krtj+|j j,s`ttj)|j j,nvt|j tkr<|jdk rttjd|jdk r`|jjdk r`ttjdn$t|j tkr|j j!dkslt"|j j!d krttj-t|j j!|jr`ttjdnt|j t.kr|j j!dkst"|j j!d kr`ttj-t|j j!nt|j t krtj%|j j&sttj'|j j&|j j(d"kr.ttj)|j j(|j j/dkrZ|j j0dkrZttj'|j j/|j j/dkrtj%|j j/ rttj'|j j/|j j0dkrtj1|j|j j0 rttj|j j0|jdkrttj|jdk r`ttjdnrt|j t2kr>tj%|j j&sttj'|j j&|j j(d#kr`ttj)|j j(n"|j dk r`ttjdt|j |jdk r|jj3r|jj3d$krttj4|jj3|jj5dk r|jj5j6|jdk rt|jt7t8t9gkrttj:t|j|jj5dk r|jj5j6|jdk r\t|jt8kr(|jj6|jnt|jt;krB|jj6|jj5dk r\|jj5j6dS)%Nr4r5z/'priority' attribute must be between %d and %d.rzno element, no actionz%no element, no source, no destinationzno action, no log, no auditzaddress and maczaddress and ipsetz mac and ipsetzinvalid sourcezinvalid destinationr<tcpudpsctpdccpzmasquerade and actionzmasquerade and mac sourcezicmp-block and actionrzforward-port and actionzUnknown element %semergalertcriterrorwarningnoticeinfodebug)r4r5)rrrr)rrrr)rrrr)rrrrrrrr)ZINVALID_SERVICErZ check_portr*Z INVALID_PORTr+ZINVALID_PROTOCOLrZ checkProtocolr,ZINVALID_ICMPTYPErr.r/Zcheck_single_addressr r1ZINVALID_LOG_LEVELr2r8r rrZINVALID_AUDIT_TYPEr)r r!r!r"r8hs                                          zRich_Rule.checkcCsd}|jr|d|j7}|jr,|d|j7}|jr@|d|j7}|jrT|d|j7}|jrh|d|j7}|jr||d|j7}|jr|d|j7}|jr|d|j7}tj rtj |S|S)Nrqz priority="%d"z family="%s"z %s) r_r7r`rarbrcrdrerZPY2Zu2b)r r$r!r!r"r%s$zRich_Rule.__str__i)NNr) r&r'r(rrr#rprfr8r%r!r!r!r"rTs o-NiiiQ)__all__ZfirewallrZfirewall.core.ipsetrZfirewall.core.baserrZfirewall.errorsrobjectrrrrr rrrrr r r r rrrrZrrr!r!r!r"s@      dPKpge[__*__pycache__/ipXtables.cpython-36.opt-1.pycnu[3 g@s(ddlZddlZddlmZddlmZddlmZm Z m Z m Z m Z m Z mZmZddlmZddlmZmZmZmZmZddlmZmZmZmZmZmZmZddl Z dZ!d d d gd d gd d d d d gd d d gd d d gdZ"dddZ#dddZ$ddZ%ddZ&ddZ'Gddde(Z)Gddde)Z*dS)N)runProg)log)tempFilereadfile splitArgs check_macportStrcheck_single_address check_address normalizeIP6)config) FirewallErrorINVALID_PASSTHROUGH INVALID_RULE UNKNOWN_ERROR INVALID_ADDR) Rich_Accept Rich_Reject Rich_Drop Rich_MarkRich_MasqueradeRich_ForwardPortRich_IcmpBlockINPUTOUTPUTFORWARD PREROUTING POSTROUTING)securityrawmanglenatfilterzicmp-host-prohibitedzicmp6-adm-prohibited)ipv4ipv6icmpz ipv6-icmpcCsddddddd}|dd}x~|D]v}y|j|}Wntk rLw$YnX|d kryt||d Wntk r~YnX|j|d ||||<q$W|S) z Inverse valid rule z-Dz--deletez-Xz--delete-chain)z-Az--appendz-Iz--insertz-Nz --new-chainN-I--insert)r'r()index Exceptionintpop)args replace_argsret_argsargidxr3/usr/lib/python3.6/ipXtables.pycommon_reverse_rule9s(  r5cCsddddddd}|dd}x|D]x}y|j|}Wntk rLw$YnX|d kryt||d Wntk r~YnX|j|d ||||<|SWttd dS) z Reverse valid passthough rule z-Dz--deletez-Xz--delete-chain)z-Az--appendz-Iz--insertz-Nz --new-chainN-I--insertr)zno '-A', '-I' or '-N' arg)r6r7)r* ValueErrorr,r-r r)r.r/r0xr2r3r3r4common_reverse_passthrough^s,   r:cCst|}tddddddddd d d d d dddddddg}t||@dkrbttdt||@dtddddddg}t||@dkrttddS)zZ Check if passthough rule is valid (only add, insert and new chain rules are allowed) z-Cz--checkz-Dz--deletez-Rz --replacez-Lz--listz-Sz --list-rulesz-Fz--flushz-Zz--zeroz-Xz--delete-chainz-Pz--policyz-Ez--rename-chainrzarg '%s' is not allowedz-Az--appendz-Iz--insertz-Nz --new-chainzno '-A', '-I' or '-N' argN)setlenr rlist)r.Z not_allowedZneededr3r3r4common_check_passthroughs*  r>c@seZdZdZdZdZddZddZddZd d Z d d Z d dZ ddZ ddZ ddZddZddZddZddZddZdd Zdhd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zdid,d-Zd.d/Zdjd1d2Zd3d4Zd5d6Zdkd8d9Zdld:d;Z dd?Z"d@dAZ#dBdCZ$dDdEZ%dFdGZ&dHdIZ'dJdKZ(dLdMZ)dNdOZ*dPdQZ+dmdRdSZ,dndTdUZ-dodVdWZ.dXdYZ/dpdZd[Z0dqd\d]Z1drd^d_Z2dsd`daZ3dbdcZ4dddeZ5dfdgZ6d!S)t ip4tablesr$TcCsd||_tj|j|_tjd|j|_|j|_|j|_ |j g|_ i|_ i|_ g|_i|_dS)Nz %s-restore)_fwr ZCOMMANDSipv_command_restore_command_detect_wait_option wait_option_detect_restore_wait_optionrestore_wait_option fill_existsavailable_tablesrich_rule_priority_countspolicy_priority_countszone_source_index_cache our_chains)selffwr3r3r4__init__s  zip4tables.__init__cCs$tjj|j|_tjj|j|_dS)N)ospathexistsrBZcommand_existsrCZrestore_command_exists)rNr3r3r4rHszip4tables.fill_existscCs|jr(|j|kr(|jgdd|D}ndd|D}tjd|j|jdj|t|j|\}}|dkrtd|jdj||f|S)NcSsg|] }d|qS)z%sr3).0itemr3r3r4 sz#ip4tables.__run..cSsg|] }d|qS)z%sr3)rTrUr3r3r4rVsz %s: %s %s rz'%s %s' failed: %s)rErdebug2 __class__rBjoinrr8)rNr.Z_argsstatusretr3r3r4Z__runszip4tables.__runc Cs<y|j|}Wntk r"dSX||||d<dSdS)NFT)r*r8)rNrulepatternZ replacementir3r3r4 _rule_replaces zip4tables._rule_replacecCs|tko|t|kS)N)BUILT_IN_CHAINS)rNrAtablechainr3r3r4is_chain_builtinszip4tables.is_chain_builtincCs2d|g}|r|jdn |jd|j||gS)Nz-tz-Nz-X)append)rNaddrcrdr^r3r3r4build_chain_ruless    zip4tables.build_chain_rulescCs8d|g}|r |d|t|g7}n |d|g7}||7}|S)Nz-tz-Iz-D)str)rNrgrcrdr*r.r^r3r3r4 build_rules  zip4tables.build_rulecCst|S)N)r5)rNr.r3r3r4 reverse_ruleszip4tables.reverse_rulecCs t|dS)N)r>)rNr.r3r3r4check_passthroughszip4tables.check_passthroughcCst|S)N)r:)rNr.r3r3r4reverse_passthroughszip4tables.reverse_passthroughcCsd}y|jd}Wntk r&YnXt||dkrD||d}d}xLd D]D}y|j|}Wntk rtYqNXt||dkrN||d}qNW||fS) Nr#z-tr]-A--append-I--insert-N --new-chain)rnrorprqrrrs)r*r8r<)rNr.rcr`rdoptr3r3r4passthrough_parse_table_chains$ z'ip4tables.passthrough_parse_table_chaincCs4yH|jd}|j||j|}d|dkr:||df}n ||df}WnFtk ry|jd}|j|d}Wntk rdSXYnXd}|ddkrd }|r| r||kr|j|nn|r0|r||kr|j||jd d d|j|}n|jjr d}nt|}d|d<|j dd|ddS)Nz%%ZONE_SOURCE%%z-mz%%ZONE_INTERFACE%%Tr-D--deleteFcSs|dS)Nrr3)r9r3r3r4&sz4ip4tables._run_replace_zone_source..)keyz-Ir)z%dr])ryrz) r*r-r8removerfsortr@_allow_zone_driftingr<insert)rNr^rLr`zoneZ zone_sourcerule_addr*r3r3r4_run_replace_zone_source s>             z"ip4tables._run_replace_zone_sourcecCsy|j|}Wntk r$YnXd}d}d}|j||j|}t|tkr\ttdd} xLdD]D} y|j| } Wntk rYqfXt|| dkrf|| d} qfWxhdD]`} y|j| }Wntk rYqXt||dkr||d} | dkrd}| dkrd}qW| | f} |sp| |ksP||| ksP|| |dkrZttd|| |d8<n| |kri|| <||| krd|| |<d} xHt || j D]4}||kr|rP| || |7} ||krPqW|| |d7<d ||<|j |dd| dS)a Change something like -t filter -I public_IN %%RICH_RULE_PRIORITY%% 123 or -t filter -A public_IN %%RICH_RULE_PRIORITY%% 321 into -t filter -I public_IN 4 or -t filter -I public_IN TFr]z%priority must be followed by a numberr#-t--table-A--append-I--insert-D--deleterz*nonexistent or underflow of priority countr)z%dN)rr)rrrrrr)rr)rr) r*r8r-typer,r rr<rsortedkeysr)rNr^Zpriority_countstokenr`rrZinsert_add_indexpriorityrcrtjrdr*pr3r3r4_set_rule_replace_priority2sj             z$ip4tables._set_rule_replace_prioritycCsPt}i}tj|j}tj|j}tj|j}x|D]}|dd} |j| dddt|jg|j| dt |jgy| j d} Wnt k rYn8X|dkrq6|d$krd d d |g| | | d <n | j | |j | |d|j | |d|j| |d} xZd%D]R} y| j | } Wnt k r,Yn(Xt| | d kr| j | | j | } qWxhtt| D]X} xPtjD]F} | | | krt| | jdo| | jd rtd| | | | <qtWqhW|j| gj| q6WxR|D]J} || }|jd| x"|D]} |jdj| dqW|jdqW|jtj|j}tjd|j|j d|j|j!fg}|j"rz|j|j"|jdt#|j ||jd\}}tj$dkr t%|j}|dk r d } xH|D]@}tj&d| |fd dd |jdstj&d!d d"| d 7} qWtj'|j|dkr:t d#|j dj||f||_||_||_dS)&Nz %%REJECT%%REJECTz --reject-withz%%ICMP%%z %%LOGTYPE%%offunicast broadcast multicastz-mpkttypez --pkt-typer]z%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%r#-t--table"z"%s"z*%s rW zCOMMIT z %s: %s %sz%s: %dz-n)stdinr)z%8d: %sr)nofmtnlr)rz'%s %s' failed: %s)rrr)rr)(rcopydeepcopyrJrKrLraDEFAULT_REJECT_TYPErAICMPr*r8r-rrr<rangestringZ whitespace startswithendswith setdefaultrfwriterZcloserQstatnamerrXrYrCst_sizerGrZgetDebugLogLevelrZdebug3unlink)rNrules log_denied temp_fileZ table_rulesrJrKrLZ_ruler^r`rcrtcrr.r[r\linesliner3r3r4 set_ruless                    zip4tables.set_rulesc Cs|j|dddt|jg|j|dt|jgy|jd}Wntk rRYn:X|dkr`dS|dkrd d d |g|||d<n |j|tj|j }tj|j }tj|j }|j ||d|j ||d|j |||j|}||_ ||_ ||_ |S)Nz %%REJECT%%rz --reject-withz%%ICMP%%z %%LOGTYPE%%rrrrrz-mrz --pkt-typer]z%%RICH_RULE_PRIORITY%%z%%POLICY_PRIORITY%%)rrr)rarrArr*r8r-rrrJrKrLrr_ip4tables__run)rNr^rr`rJrKrLoutputr3r3r4set_rules.      zip4tables.set_ruleNc Csg}|r|gntj}xx|D]p}||jkr6|j|qy,|jd|ddg|jj||j|Wqtk rtjd|j|fYqXqW|S)Nz-tz-Lz-nzA%s table '%s' does not exist (or not enough permission to check).) rbrrIrfrr8rdebug1rA)rNrcr\Ztablesr3r3r4get_available_tabless    zip4tables.get_available_tablescCs`d}t|jdddg}|ddkr\d}t|jdddg}|ddkrHd}tjd|j|j||S)Nrz-wz-Lz-nrz-w10z%s: %s will be using %s option.)rrBrrXrY)rNrEr\r3r3r4rDs  zip4tables._detect_wait_optioncCst}|jd|jd}xJd D]B}t|j|g|jd}|ddkr"d|dkr"d |dkr"|}Pq"Wtjd |j|j|t j |j|S) Nz#foor-w--wait=2)rrzinvalid optionr]zunrecognized optionz%s: %s will be using %s option.)rr) rrrrrCrrrXrYrQr)rNrrEZ test_optionr\r3r3r4rF"s    z%ip4tables._detect_restore_wait_optioncCsVi|_i|_g|_g}x:tjD].}|j|s0q xdD]}|jd||gq6Wq W|S)N-F-X-Zz-t)rrr)rJrKrLrbrrrf)rNrrcflagr3r3r4build_flush_rules5s  zip4tables.build_flush_rulescCsfg}|dkrdn|}xLtjD]@}|j|s.q|dkr8qx$t|D]}|jd|d||gqBWqW|S)NZPANICDROPr"z-tz-P)rbrrrf)rNpolicyr_policyrcrdr3r3r4build_set_policy_rulesDs z ip4tables.build_set_policy_rulesc Cs g}d}y"|jd|jdkrdnddg}WnJtk rt}z.|jdkrVtjd|ntjd|WYd d }~XnX|j}d }x|D]}|r|jj}|j}xD|D]<} | j d r| j d r| d d} n| } | |kr|j | qW|jdko|j ds|jdkr|j drd}qW|S)zQReturn ICMP types that are supported by the iptables/ip6tables command and kernelrz-pr$r&z ipv6-icmpz--helpziptables error: %szip6tables error: %sNF()r]zValid ICMP Types:r%zValid ICMPv6 Types:Tr) rrAr8rr splitlinesstriplowersplitrrrf) rNrAr\rZexrZin_typesrZsplitsrr9r3r3r4supported_icmp_typesPs4      zip4tables.supported_icmp_typescCsgS)Nr3)rNr3r3r4build_default_tablesqszip4tables.build_default_tablesrc Csi}|jdrpg|d<t|jd<xLtdD]@}|djd||djd||f|jdjd|q,W|jdr\g|d<t|jd<xtdD]}|djd||djd||f|jdjd||dkrxt|jjrddd d gndd d gD]R}|djd ||f|djd |||f|jdjtd ||fgqWqW|jdrNg|d<t|jd<xtdD]}|djd||djd||f|jdjd||dkrxv|jjrddd d gndd d gD]R}|djd ||f|djd |||f|jdjtd ||fgqWqW|jdr@g|d<t|jd<xtdD]}|djd||djd||f|jdjd||d9krxxv|jjrddd d gndd d gD]R}|djd ||f|djd |||f|jdjtd ||fgqWqxWg|d<t|jd<|djd|djd|djd|djd|jdjtdxf|jjrddd d gndd d gD]B}|djd||djd||jdjtd|qW|dkr |djd|djd|dkrF|djd|djd|djd|djd |djd!|djd"|jdjtd#xJd:D]B}|djd$||djd%||jdjtd&|qWxzd;D]r}xj|jjr dd gnd gD]N}|djd)||f|djd*||f|jdjtd+||fqWqWxJdD]B}|djd5||djd6||jdjtd7|q~Wg}xJ|D]B}||jkrqx(||D]}|jd8|gt |qWqW|S)?Nrz -N %s_directz-A %s -j %s_directz %s_directr r POLICIES_preZ ZONES_SOURCEZZONES POLICIES_postz-N %s_%sz-A %s -j %s_%sz%s_%sr!r"rr#zB-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPTz-A INPUT -i lo -j ACCEPTz-N INPUT_directz-A INPUT -j INPUT_directZ INPUT_directz -N INPUT_%sz-A INPUT -j INPUT_%szINPUT_%srz^-A INPUT -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: 'z/-A INPUT -m conntrack --ctstate INVALID -j DROPz9-A INPUT %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: 'z-A INPUT -j %%REJECT%%zD-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED,DNAT -j ACCEPTz-A FORWARD -i lo -j ACCEPTz-N FORWARD_directz-A FORWARD -j FORWARD_directZFORWARD_directz -N FORWARD_%sz-A FORWARD -j FORWARD_%sz FORWARD_%sINOUTz-N FORWARD_%s_%sz-A FORWARD -j FORWARD_%s_%sz FORWARD_%s_%sz`-A FORWARD -m conntrack --ctstate INVALID %%LOGTYPE%% -j LOG --log-prefix 'STATE_INVALID_DROP: 'z1-A FORWARD -m conntrack --ctstate INVALID -j DROPz;-A FORWARD %%LOGTYPE%% -j LOG --log-prefix 'FINAL_REJECT: 'z-A FORWARD -j %%REJECT%%z-N OUTPUT_directz>-A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPTz-A OUTPUT -o lo -j ACCEPTz-A OUTPUT -j OUTPUT_directZ OUTPUT_directz -N OUTPUT_%sz-A OUTPUT -j OUTPUT_%sz OUTPUT_%sz-t)rr)r)rr)r)r)r) rr;rMrbrfrgr@rupdater) rNrZ default_rulesrdZdispatch_suffix directionZfinal_default_rulesrcr^r3r3r4build_default_rulesus    $(   &*   &* &    (       "zip4tables.build_default_rulescCsf|dkrdddhS|dkr,d|jkr,dhS|dkrHd|jkrHddhS|d krbd |jkrbdhSiS) Nr#r FORWARD_IN FORWARD_OUTr!rr"rr )r)rNrcr3r3r4get_zone_table_chainss    zip4tables.get_zone_table_chainsc s|jjj|jdkrdnddkr4dkr4dnd} |jjj|t| g} g} x|D]} | jd| gqZWx|D]} | jd | gqvWxB|D]:} |jjj| }|dkr|j | rq| j|j d | qWx\|D]T} |jjj| }|dkr|j | rqt | rdkrq| j|j d| qWfdd}g}| rx| D]F}| rx8| D]}|j|||qdWn|rn|j||dqTWnH|rn@| rx8| D]}|j|d|qWn|rn|j|dd|S)Nrprepostr"rTFz-iz-or$r%z-srrz-dcsVddd}d|dfdjg}|r6|j||rD|j||jdg|S)Nz-Az-D)TFz-tz%s_POLICIES_%sz%%POLICY_PRIORITY%%z-j)rextend)ingress_fragmentegress_fragmentadd_delr^)rrd chain_suffixenablep_objrcr3r4_generate_policy_dispatch_rules   zSip4tables.build_policy_ingress_egress_rules.._generate_policy_dispatch_rule)r$r%)r$r%)rrr) r@rZ get_policyrpolicy_base_chain_namePOLICY_CHAIN_PREFIXrfrZ check_sourceis_ipv_supported_rule_addr_fragmentr)rNrrrcrdZingress_interfacesZegress_interfacesZingress_sourcesZegress_sourcesisSNATZingress_fragmentsZegress_fragments interfaceaddrrArrrrr3)rrdrrrrcr4!build_policy_ingress_egress_rulessR        z+ip4tables.build_policy_ingress_egress_rulesFc Cs|dkr|dkrdnd}|jjj||t|d} ddddddd|} d } |rb| rbd d |d g} n,|rtd d |g} ndd |g} |s| d g7} | d|| || | g7} | gS)Nr"rTF)rz-iz-o)rrrrrrz-gz-Iz%s_ZONESz%%ZONE_INTERFACE%%z-Az-Dz-t)r@rrr) rNrrrrrcrdrfrrrtactionr^r3r3r4!build_zone_source_interface_rulesKs&   z+ip4tables.build_zone_source_interface_rulescCs|jdrP|dd}|dkr$d}nd}dj|g|jjj|}ddd ||gSt|rz|dkrjttd dd d |jgSt d |rt |}n,t d |r|j d}t |dd|d}||gSdS)Nzipset:z-ddstsrc,z-mr;z --match-setzCan't match a destination MAC.macz --mac-sourcer%/rr]) rrZr@ipsetZ get_dimensionrr rupperr r r r)rNrtaddressinvertrflags addr_splitr3r3r4res"       zip4tables._rule_addr_fragmentc Csddd|}|dkr"|dkr"dnd}|jjj||t|d} d d d d d d d |} |jjrdd |} nd |} t|r|dkrgS|| d|d|g} | j|j| || jd| g| gS)Nz-Iz-D)TFr"rTF)rz-sz-d)rrrrrrz%s_ZONES_SOURCEz%s_ZONESrrz%%ZONE_SOURCE%%z-tz-g)rrr)r@rrrrrrr) rNrrrrrcrdrrrrtZzone_dispatch_chainr^r3r3r4build_zone_source_address_rules{s& z)ip4tables.build_zone_source_address_rulesc Cs>ddd|}ddd|}|dkr0|dkr0dnd }|jjj||t|d }|j|jt|d |d |d |d|d|gg} | j||d|g| j|d |d|g| j|d |d|g| j|d |d|g| j|d|d|g| j|d|d|g| j||d|dd |g| j||d|dd |g| j||d|dd |g| j||d|dd|g| j||d|dd|g|jjj|j } |jj dkr|dkr| dkr| j||d|ddddd|g | dkr| j||d|ddddd|g |dkr,| dkr,| j||d|d| g|s:| j | S)Nz-Nz-X)TFz-Az-Dr"rTF)rz%s_logz%s_denyz%s_prez%s_postz%s_allowz-tz-jrr#r %%REJECT%%z %%LOGTYPE%%LOGz --log-prefixz "%s_REJECT: "rz "%s_DROP: "ACCEPT)rr)rrrr) r@rrrrMrr;rfZ _policiestargetget_log_deniedreverse) rNrrrcrdZ add_del_chainZ add_del_rulerrrrr3r3r4build_policy_chain_rulessN       z"ip4tables.build_policy_chain_rulescCs2|sgSddd|jg}|jdk r.|d|jg7}|S)Nz-mlimitz--limitz --limit-burst)valueZburst)rNrsr3r3r4 _rule_limits  zip4tables._rule_limitcCst|jtttgkrn<|jrHt|jtttt gkrRt t dt|jn t t d|j dkrt|jttgkst|jtt gkrdSt|jtgkst|jttgkrdSn|j dkrdSdSdS)NzUnknown action %szNo rule action specified.rallowZdenyrr) relementrrrrrrrrr rr)rN rich_ruler3r3r4_rich_rule_chain_suffixs    z!ip4tables._rich_rule_chain_suffixcCs>|j r|j rttd|jdkr(dS|jdkr6dSdSdS)NzNot log or auditrrrr)rauditr rr)rNrr3r3r4 _rich_rule_chain_suffix_from_logs   z*ip4tables._rich_rule_chain_suffix_from_logcCs|jdkrgSd|jgS)Nrz%%RICH_RULE_PRIORITY%%)r)rNrr3r3r4_rich_rule_priority_fragments z&ip4tables._rich_rule_priority_fragmentc Cs|js gS|jjj||t}ddd|}|j|}d||d||fg} | |j|7} | |ddg7} |jjr| dd |jjg7} |jjr| d d |jjg7} | |j |jj 7} | S) Nz-Az-D)TFz-tz%s_%sz-jrz --log-prefixz'%s'z --log-levelz%s) rr@rrrr r prefixlevelrr) rNrrrrc rule_fragmentrrrr^r3r3r4_rich_rule_logs zip4tables._rich_rule_logc Cs|js gSddd|}|jjj||t}|j|}d||d||fg} | |j|7} | |7} t|jt krrd} n,t|jt krd} nt|jt krd} nd } | d d d | g7} | |j |jj 7} | S) Nz-Az-D)TFz-tz%s_%sZacceptZrejectZdropunknownz-jZAUDITz--type)r r@rrrr r rrrrrrr) rNrrrrcrrrrr^Z_typer3r3r4_rich_rule_audit s$ zip4tables._rich_rule_auditc Cs2|js gSddd|}|jjj||t}|j|}d||f} t|jtkrXddg} nt|jtkrddg} |jjr| d|jjg7} nnt|jt krdd g} nVt|jt krd }|jjj||t}d||f} dd d |jj g} nt t d t|jd||| g} | |j|7} | || 7} | |j|jj7} | S)Nz-Az-D)TFz%s_%sz-jrrz --reject-withrr!MARKz --set-xmarkzUnknown action %sz-t)rr@rrrr rrrrrr;r rr rr) rNrrrrcrrrrrdZ rule_actionr^r3r3r4_rich_rule_action$s4       zip4tables._rich_rule_actioncCs|sgSg}|jr|jr"|jdtd|jrB|dt|jg7}qtd|jr||jjd}|dt|dd|dg7}q|d|jg7}nD|jr|ddg7}|jr|jd|jj j |jd }|d |j|g7}|S) N!r%z-drrr]z-mr;rz --match-set) rrrfr r r rrr@r_ipset_match_flags)rNZ rich_destrrrr3r3r4_rich_rule_destination_fragmentFs&    "  z)ip4tables._rich_rule_destination_fragmentcCs|sgSg}|jr|jr"|jdtd|jrB|dt|jg7}nHtd|jr||jjd}|dt|dd|dg7}n|d|jg7}nt|dr|jr|ddg7}|jr|jd|d |jg7}nPt|d o|j r|dd g7}|jr|jd|j j j |j d }|d |j |g7}|S)Nrr%z-srrr]rz-mz --mac-sourcerr;rz --match-set) rrrfr r r rhasattrrrr@rr)rNZ rich_sourcerrrr3r3r4_rich_rule_source_fragment^s0    "    z$ip4tables._rich_rule_source_fragmentc Csddd|}d}|jjj||t} d|g} |rD| ddt|g7} |rT| d|g7} |rx| |j|j7} | |j|j7} | st |j t kr| d d d d g7} g} |r| j |j ||||| | j |j||||| | j |j||||| n"| j |d | d|g| ddg| S)Nz-Az-D)TFr#z-pz--dportz%sz-dz-m conntrackz --ctstatez NEW,UNTRACKEDz%s_allowz-tz-jr)r@rrrrr destinationrsourcerrrrfrrr) rNrrprotoportrrrrcrrrr3r3r4build_policy_ports_rules{s* z"ip4tables.build_policy_ports_rulesc Csddd|}d}|jjj||t}d|g} |r<| d|g7} |r`| |j|j7} | |j|j7} | stt|j t kr| ddd d g7} g} |r| j |j ||||| | j |j ||||| | j |j||||| n"| j |d |d |g| d dg| S)Nz-Az-D)TFr#z-pz-dz-mrz --ctstatez NEW,UNTRACKEDz%s_allowz-tz-jr)r@rrrrrrrrrrrfrrr) rNrrprotocolrrrrcrrrr3r3r4build_policy_protocol_ruless& z%ip4tables.build_policy_protocol_rulesc Csddd|}d}|jjj||t} d|g} |rD| ddt|g7} |rT| d|g7} |rx| |j|j7} | |j|j7} | st |j t kr| d d d d g7} g} |r| j |j ||||| | j |j||||| | j |j||||| n"| j |d | d|g| ddg| S)Nz-Az-D)TFr#z-pz--sportz%sz-dz-mrz --ctstatez NEW,UNTRACKEDz%s_allowz-tz-jr)r@rrrrrrrrrrrrfrrr) rNrrrrrrrrcrrrr3r3r4build_policy_source_ports_ruless* z)ip4tables.build_policy_source_ports_rulesc Csvd}|jjj||t} ddd|} | d| ddd|g} |rP| dd t|g7} |r`| d |g7} | d d d |g7} | gS)Nr z-Az-D)TFz%s_allowz-tz-pz--dportz%sz-dz-jZCTz--helper)r@rrrr) rNrrrrrZ helper_nameZmodule_short_namercrrr^r3r3r4build_policy_helper_ports_ruless z)ip4tables.build_policy_helper_ports_rulesc Csddd|}|jjj||t}g} |rH| jdd|d|d|dd gn6t|rTgS| jdd|d|g|jd |dd g| S) Nz-Az-D)TFz-tr#z%s_allowz-oz-jrz-d)r@rrrrfrr) rNrrrrcrrrrrr3r3r4build_zone_forward_ruless z"ip4tables.build_zone_forward_rulesc Cs,d}|jjj||tdd}ddd|}g}|rj|j|}||j|7}||j|j7}||j|j 7}nd}g} | j dd|d ||fg|d d d d dgg}|r|j|}||j|7}||j|j7}||j|j 7}nd}d}|jjj||t}| j dd|d ||fg|ddddd dg| S)Nr"T)rz-Az-D)TFrz-tz%s_%srz-oloz-jZ MASQUERADEr#z-mrz --ctstatez NEW,UNTRACKEDr) r@rrrr r rrrrrf) rNrrrrcrrrrrr3r3r4build_policy_masquerade_ruless6  z'ip4tables.build_policy_masquerade_rulesc Cs d}|jjj||t} ddd|} d} |rPtd|rH| dt|7} n| |7} |rn|dkrn| dt|d 7} g} |r|j|} |j|} | |j |j 7} | |j |j 7} nd } g}|r|j |j|||d| |j d d| d | | fg| d |dt|ddd| g|S)Nr"z-Az-D)TFrr%z[%s]z:%s-rz-tz%s_%sz-pz--dportz-jZDNATz--to-destination)r@rrrr r rr r rrrrrfr)rNrrrr ZtoportZtoaddrrrcrrZtorrrr3r3r4build_policy_forward_port_ruless2     z)ip4tables.build_policy_forward_port_rulescCsd}|jjj||t}ddd|}|jdkrFddg}ddd |jg} ndd g}dd d |jg} g} |jjj|r|d |} d} n d|} d} g} |r| |j|j7} | |j |j 7} | || 7} |rP| j |j ||||| | j |j ||||| |jr| j |j||||| n:|j|}| j d||d||fg|j|| ddgn`|jjdkr| dkr| j || d|g| ddddd|g| j || d|g| d| g| S)Nr#z-Az-D)TFr$z-pr&z-mz --icmp-typez ipv6-icmpZicmp6z --icmpv6-typez%s_allowrz%s_denyz %%REJECT%%z-tz%s_%sz-jrz %%LOGTYPE%%rz --log-prefixz"%s_ICMP_BLOCK: ")r@rrrrArquery_icmp_block_inversionrrrrrfrrrrr r r)rNrrZictrrcrrrmatchrZ final_chainZ final_targetrrr3r3r4build_policy_icmp_block_rules3sJ     z'ip4tables.build_policy_icmp_block_rulesc Csd}|jjj||t}g}d}|jjj|rd}|jjdkr|rRd|t|g}nd|g}|d|dd d d d d d|g }|j||d7}nd}|rd|t|g}nd|g}|d|dd d |g}|j||S)Nr#rz %%REJECT%%rz-Iz-Dz-tz-pz%%ICMP%%z %%LOGTYPE%%z-jrz --log-prefixz"%s_ICMP_BLOCK: "r]r)r@rrrr)rrirf) rNrrrcrrZrule_idxZ ibi_targetr^r3r3r4'build_policy_icmp_block_inversion_rulesds.     z1ip4tables.build_policy_icmp_block_inversion_rulescCsxd}g}||j|j7}||j|j7}g}|j|j||||||j|j||||||j|j||||||S)Nr#)rrrrrfrrr)rNrrrrcrrr3r3r4*build_policy_rich_source_destination_rulessz4ip4tables.build_policy_rich_source_destination_rulescCs ||jkS)N)rA)rNrAr3r3r4rszip4tables.is_ipv_supported)N)N)r)F)F)NN)NN)NN)NN)N)N)N)7__name__ __module__ __qualname__rArZpolicies_supportedrPrHrrarerhrjrkrlrmrurrrrrrDrFrrrrrrrrrrrrr r r rrrrrrr!r"r#r$r&r(r+r,r-rr3r3r3r4r?sh     )Pa#   ! zN  0 "     & ! 1"r?c@s&eZdZdZdZdddZddZdS) ip6tablesr%Fc Csg}|jddddddddd d g |d krL|jddddddddd d d dg |jdddddddd dg |jdddddddd dg |S)Nz-Irz-tr!z-mZrpfilterz--invertz --validmarkz-jrrrz --log-prefixzrpfilter_DROP: z-pz ipv6-icmpz$--icmpv6-type=neighbour-solicitationrz"--icmpv6-type=router-advertisement)rf)rNrrr3r3r4build_rpfilter_ruless$        zip6tables.build_rpfilter_rulesc Csddddddddd g }d }|jd j|g}|jd d d |gxT|D]L}|jd d d|d|ddddg |jjdkrF|jd d d|d|ddddg qFW|jd d dddd|g|jd d dddd|g|S)Nz ::0.0.0.0/96z::ffff:0.0.0.0/96z2002:0000::/24z2002:0a00::/24z2002:7f00::/24z2002:ac10::/28z2002:c0a8::/32z2002:a9fe::/32z2002:e000::/19Z RFC3964_IPv4r#z-tz-Nz-Iz-dz-jrz --reject-withz addr-unreachrallrz --log-prefixz"RFC3964_IPv4_REJECT: "r4r)rr3)rMrgrfr@Z _log_denied)rNZ daddr_listZ chain_namerZdaddrr3r3r4build_rfc3964_ipv4_ruless4       z"ip6tables.build_rfc3964_ipv4_rulesN)F)r.r/r0rArr2r5r3r3r3r4r1s r1)+Zos.pathrQrZfirewall.core.progrZfirewall.core.loggerrZfirewall.functionsrrrrrr r r Zfirewallr Zfirewall.errorsr rrrrZfirewall.core.richrrrrrrrrrrbrrr5r:r>objectr?r1r3r3r3r4s@  ( $ %* xPKpge[G@ @ "__pycache__/modules.cpython-36.pycnu[3 g@sBdZdgZddlmZddlmZddlmZGdddeZ dS)zmodules backendmodules)runProg)log)COMMANDSc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)rcCstd|_td|_dS)NZmodprobeZrmmod)r _load_command_unload_command)selfr /usr/lib/python3.6/modules.py__init__s zmodules.__init__cCs d|jS)Nz%s) __class__)rr r r __repr__$szmodules.__repr__cCsg}i}ytddp}xh|D]`}|s&P|j}|j}|j|d|ddkrp|djddd ||d<qg||d<qWWdQRXWntk rYnX||fS) z6 get all loaded kernel modules and their dependencies z /proc/modulesrr-,N)openstripsplitappendFileNotFoundError)rmodsdepsflineZsplitsr r r loaded_modules's     zmodules.loaded_modulescCs"tjd|j|j|t|j|gS)Nz %s: %s %s)rdebug2r rr)rmoduler r r load_module<szmodules.load_modulecCs"tjd|j|j|t|j|gS)Nz %s: %s %s)rrr rr)rrr r r unload_module@szmodules.unload_modulecCsT||kr dSx0||D]$}|j|||||kr|j|qW||krP|j|dS)z get all dependants of a module N)get_depsr)rrrretmodr r r r"Dszmodules.get_depscCsg}|j\}}|jd||x*dD]"}||kr$|j||jd|q$Wx^|D]V}|dks|jds|jd s|jd s|jd s|jd s|jd rP|j|||qPW|S)z) get all loaded firewall-related modules Z nf_conntracknf_conntrack_ipv4nf_conntrack_ipv6r ip_tables ip6_tablesebtablesZiptable_Z ip6table_Znf_Zxt_Zipt_Zip6t_)r%r&r)r'r(r))rr"removeinsert startswith)rrZmods2rZbad_bad_moduler$r r r get_firewall_modulesOs    zmodules.get_firewall_modulescCs>x8|jD],}|j|\}}|dkr tjd||fq WdS)z% unload all firewall-related modules rz Failed to unload module '%s': %sN)r-r!rZdebug1)rrZstatusr#r r r unload_firewall_modulesdszmodules.unload_firewall_modulesN) __name__ __module__ __qualname__r r rr r!r"r-r.r r r r rs N) __doc____all__Zfirewall.core.progrZfirewall.core.loggerrZfirewall.configrobjectrr r r r s    PKpge[1 fw_policies.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "FirewallPolicies" ] from firewall import config from firewall.core.logger import log from firewall.core.io.lockdown_whitelist import LockdownWhitelist from firewall import errors from firewall.errors import FirewallError class FirewallPolicies(object): def __init__(self): self._lockdown = False self.lockdown_whitelist = LockdownWhitelist(config.LOCKDOWN_WHITELIST) def __repr__(self): return '%s(%r, %r)' % (self.__class__, self._lockdown, self.lockdown_whitelist) def cleanup(self): self._lockdown = False self.lockdown_whitelist.cleanup() # lockdown def access_check(self, key, value): if key == "context": log.debug2('Doing access check for context "%s"' % value) if self.lockdown_whitelist.match_context(value): log.debug3('context matches.') return True elif key == "uid": log.debug2('Doing access check for uid %d' % value) if self.lockdown_whitelist.match_uid(value): log.debug3('uid matches.') return True elif key == "user": log.debug2('Doing access check for user "%s"' % value) if self.lockdown_whitelist.match_user(value): log.debug3('user matches.') return True elif key == "command": log.debug2('Doing access check for command "%s"' % value) if self.lockdown_whitelist.match_command(value): log.debug3('command matches.') return True return False def enable_lockdown(self): if self._lockdown: raise FirewallError(errors.ALREADY_ENABLED, "enable_lockdown()") self._lockdown = True def disable_lockdown(self): if not self._lockdown: raise FirewallError(errors.NOT_ENABLED, "disable_lockdown()") self._lockdown = False def query_lockdown(self): return self._lockdown PKpge[*yyio/functions.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2018 Red Hat, Inc. # # Authors: # Eric Garver # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import os from firewall import config from firewall.errors import FirewallError from firewall.core.fw_config import FirewallConfig from firewall.core.io.zone import zone_reader from firewall.core.io.service import service_reader from firewall.core.io.ipset import ipset_reader from firewall.core.io.icmptype import icmptype_reader from firewall.core.io.helper import helper_reader from firewall.core.io.policy import policy_reader from firewall.core.io.direct import Direct from firewall.core.io.lockdown_whitelist import LockdownWhitelist from firewall.core.io.firewalld_conf import firewalld_conf def check_config(fw): fw_config = FirewallConfig(fw) readers = { "ipset": {"reader": ipset_reader, "add": fw_config.add_ipset, "dirs": [config.FIREWALLD_IPSETS, config.ETC_FIREWALLD_IPSETS], }, "helper": {"reader": helper_reader, "add": fw_config.add_helper, "dirs": [config.FIREWALLD_HELPERS, config.ETC_FIREWALLD_HELPERS], }, "icmptype": {"reader": icmptype_reader, "add": fw_config.add_icmptype, "dirs": [config.FIREWALLD_ICMPTYPES, config.ETC_FIREWALLD_ICMPTYPES], }, "service": {"reader": service_reader, "add": fw_config.add_service, "dirs": [config.FIREWALLD_SERVICES, config.ETC_FIREWALLD_SERVICES], }, "zone": {"reader": zone_reader, "add": fw_config.add_zone, "dirs": [config.FIREWALLD_ZONES, config.ETC_FIREWALLD_ZONES], }, "policy": {"reader": policy_reader, "add": fw_config.add_policy_object, "dirs": [config.FIREWALLD_POLICIES, config.ETC_FIREWALLD_POLICIES], }, } for reader in readers.keys(): for _dir in readers[reader]["dirs"]: if not os.path.isdir(_dir): continue for file in sorted(os.listdir(_dir)): if file.endswith(".xml"): try: obj = readers[reader]["reader"](file, _dir) if reader in ["zone", "policy"]: obj.fw_config = fw_config obj.check_config_dict(obj.export_config_dict()) readers[reader]["add"](obj) except FirewallError as error: raise FirewallError(error.code, "'%s': %s" % (file, error.msg)) except Exception as msg: raise Exception("'%s': %s" % (file, msg)) if os.path.isfile(config.FIREWALLD_DIRECT): try: obj = Direct(config.FIREWALLD_DIRECT) obj.read() obj.check_config(obj.export_config()) except FirewallError as error: raise FirewallError(error.code, "'%s': %s" % (config.FIREWALLD_DIRECT, error.msg)) except Exception as msg: raise Exception("'%s': %s" % (config.FIREWALLD_DIRECT, msg)) if os.path.isfile(config.LOCKDOWN_WHITELIST): try: obj = LockdownWhitelist(config.LOCKDOWN_WHITELIST) obj.read() obj.check_config(obj.export_config()) except FirewallError as error: raise FirewallError(error.code, "'%s': %s" % (config.LOCKDOWN_WHITELIST, error.msg)) except Exception as msg: raise Exception("'%s': %s" % (config.LOCKDOWN_WHITELIST, msg)) if os.path.isfile(config.FIREWALLD_CONF): try: obj = firewalld_conf(config.FIREWALLD_CONF) obj.read() except FirewallError as error: raise FirewallError(error.code, "'%s': %s" % (config.FIREWALLD_CONF, error.msg)) except Exception as msg: raise Exception("'%s': %s" % (config.FIREWALLD_CONF, msg)) PKpge[9155io/firewalld_conf.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2012 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import os.path import io import tempfile import shutil from firewall import config from firewall.core.logger import log from firewall.functions import b2u, u2b, PY2 valid_keys = [ "DefaultZone", "MinimalMark", "CleanupOnExit", "CleanupModulesOnExit", "Lockdown", "IPv6_rpfilter", "IndividualCalls", "LogDenied", "AutomaticHelpers", "FirewallBackend", "FlushAllOnReload", "RFC3964_IPv4", "AllowZoneDrifting" ] class firewalld_conf(object): def __init__(self, filename): self._config = { } self._deleted = [ ] self.filename = filename self.clear() def clear(self): self._config = { } self._deleted = [ ] def cleanup(self): self._config.clear() self._deleted = [ ] def get(self, key): return self._config.get(key.strip()) def set(self, key, value): _key = b2u(key.strip()) self._config[_key] = b2u(value.strip()) if _key in self._deleted: self._deleted.remove(_key) def __str__(self): s = "" for (key,value) in self._config.items(): if s: s += '\n' s += '%s=%s' % (key, value) return u2b(s) if PY2 else s # load self.filename def read(self): self.clear() try: f = open(self.filename, "r") except Exception as msg: log.error("Failed to load '%s': %s", self.filename, msg) self.set("DefaultZone", config.FALLBACK_ZONE) self.set("MinimalMark", str(config.FALLBACK_MINIMAL_MARK)) self.set("CleanupOnExit", "yes" if config.FALLBACK_CLEANUP_ON_EXIT else "no") self.set("CleanupModulesOnExit", "yes" if config.FALLBACK_CLEANUP_MODULES_ON_EXIT else "no") self.set("Lockdown", "yes" if config.FALLBACK_LOCKDOWN else "no") self.set("IPv6_rpfilter","yes" if config.FALLBACK_IPV6_RPFILTER else "no") self.set("IndividualCalls", "yes" if config.FALLBACK_INDIVIDUAL_CALLS else "no") self.set("LogDenied", config.FALLBACK_LOG_DENIED) self.set("AutomaticHelpers", config.FALLBACK_AUTOMATIC_HELPERS) self.set("FirewallBackend", config.FALLBACK_FIREWALL_BACKEND) self.set("FlushAllOnReload", "yes" if config.FALLBACK_FLUSH_ALL_ON_RELOAD else "no") self.set("RFC3964_IPv4", "yes" if config.FALLBACK_RFC3964_IPV4 else "no") self.set("AllowZoneDrifting", "yes" if config.FALLBACK_ALLOW_ZONE_DRIFTING else "no") raise for line in f: if not line: break line = line.strip() if len(line) < 1 or line[0] in ['#', ';']: continue # get key/value pair pair = [ x.strip() for x in line.split("=") ] if len(pair) != 2: log.error("Invalid option definition: '%s'", line.strip()) continue elif pair[0] not in valid_keys: log.error("Invalid option: '%s'", line.strip()) continue elif pair[1] == '': log.error("Missing value: '%s'", line.strip()) continue elif self._config.get(pair[0]) is not None: log.error("Duplicate option definition: '%s'", line.strip()) continue self._config[pair[0]] = pair[1] f.close() # check default zone if not self.get("DefaultZone"): log.error("DefaultZone is not set, using default value '%s'", config.FALLBACK_ZONE) self.set("DefaultZone", str(config.FALLBACK_ZONE)) # check minimal mark value = self.get("MinimalMark") try: int(value) except (ValueError, TypeError): if value is not None: log.warning("MinimalMark '%s' is not valid, using default " "value '%d'", value if value else '', config.FALLBACK_MINIMAL_MARK) self.set("MinimalMark", str(config.FALLBACK_MINIMAL_MARK)) # check cleanup on exit value = self.get("CleanupOnExit") if not value or value.lower() not in [ "no", "false", "yes", "true" ]: if value is not None: log.warning("CleanupOnExit '%s' is not valid, using default " "value %s", value if value else '', config.FALLBACK_CLEANUP_ON_EXIT) self.set("CleanupOnExit", "yes" if config.FALLBACK_CLEANUP_ON_EXIT else "no") # check module cleanup on exit value = self.get("CleanupModulesOnExit") if not value or value.lower() not in [ "no", "false", "yes", "true" ]: if value is not None: log.warning("CleanupModulesOnExit '%s' is not valid, using default " "value %s", value if value else '', config.FALLBACK_CLEANUP_MODULES_ON_EXIT) self.set("CleanupModulesOnExit", "yes" if config.FALLBACK_CLEANUP_MODULES_ON_EXIT else "no") # check lockdown value = self.get("Lockdown") if not value or value.lower() not in [ "yes", "true", "no", "false" ]: if value is not None: log.warning("Lockdown '%s' is not valid, using default " "value %s", value if value else '', config.FALLBACK_LOCKDOWN) self.set("Lockdown", "yes" if config.FALLBACK_LOCKDOWN else "no") # check ipv6_rpfilter value = self.get("IPv6_rpfilter") if not value or value.lower() not in [ "yes", "true", "no", "false" ]: if value is not None: log.warning("IPv6_rpfilter '%s' is not valid, using default " "value %s", value if value else '', config.FALLBACK_IPV6_RPFILTER) self.set("IPv6_rpfilter","yes" if config.FALLBACK_IPV6_RPFILTER else "no") # check individual calls value = self.get("IndividualCalls") if not value or value.lower() not in [ "yes", "true", "no", "false" ]: if value is not None: log.warning("IndividualCalls '%s' is not valid, using default " "value %s", value if value else '', config.FALLBACK_INDIVIDUAL_CALLS) self.set("IndividualCalls", "yes" if config.FALLBACK_INDIVIDUAL_CALLS else "no") # check log denied value = self.get("LogDenied") if not value or value not in config.LOG_DENIED_VALUES: if value is not None: log.warning("LogDenied '%s' is invalid, using default value '%s'", value, config.FALLBACK_LOG_DENIED) self.set("LogDenied", str(config.FALLBACK_LOG_DENIED)) # check automatic helpers value = self.get("AutomaticHelpers") if not value or value.lower() not in config.AUTOMATIC_HELPERS_VALUES: if value is not None: log.warning("AutomaticHelpers '%s' is not valid, using default " "value %s", value if value else '', config.FALLBACK_AUTOMATIC_HELPERS) self.set("AutomaticHelpers", str(config.FALLBACK_AUTOMATIC_HELPERS)) value = self.get("FirewallBackend") if not value or value.lower() not in config.FIREWALL_BACKEND_VALUES: if value is not None: log.warning("FirewallBackend '%s' is not valid, using default " "value %s", value if value else '', config.FALLBACK_FIREWALL_BACKEND) self.set("FirewallBackend", str(config.FALLBACK_FIREWALL_BACKEND)) value = self.get("FlushAllOnReload") if not value or value.lower() not in [ "yes", "true", "no", "false" ]: if value is not None: log.warning("FlushAllOnReload '%s' is not valid, using default " "value %s", value if value else '', config.FALLBACK_FLUSH_ALL_ON_RELOAD) self.set("FlushAllOnReload", str(config.FALLBACK_FLUSH_ALL_ON_RELOAD)) value = self.get("RFC3964_IPv4") if not value or value.lower() not in [ "yes", "true", "no", "false" ]: if value is not None: log.warning("RFC3964_IPv4 '%s' is not valid, using default " "value %s", value if value else '', config.FALLBACK_RFC3964_IPV4) self.set("RFC3964_IPv4", str(config.FALLBACK_RFC3964_IPV4)) value = self.get("AllowZoneDrifting") if not value or value.lower() not in [ "yes", "true", "no", "false" ]: if value is not None: log.warning("AllowZoneDrifting '%s' is not valid, using default " "value %s", value if value else '', config.FALLBACK_ALLOW_ZONE_DRIFTING) self.set("AllowZoneDrifting", str(config.FALLBACK_ALLOW_ZONE_DRIFTING)) # save to self.filename if there are key/value changes def write(self): if len(self._config) < 1: # no changes: nothing to do return # handled keys done = [ ] if not os.path.exists(config.ETC_FIREWALLD): os.mkdir(config.ETC_FIREWALLD, 0o750) try: temp_file = tempfile.NamedTemporaryFile(mode='wt', prefix="%s." % os.path.basename(self.filename), dir=os.path.dirname(self.filename), delete=False) except Exception as msg: log.error("Failed to open temporary file: %s" % msg) raise modified = False empty = False try: f= io.open(self.filename, mode='rt', encoding='UTF-8') except Exception as msg: if os.path.exists(self.filename): log.error("Failed to open '%s': %s" % (self.filename, msg)) raise else: f = None else: for line in f: if not line: break # remove newline line = line.strip("\n") if len(line) < 1: if not empty: temp_file.write(u"\n") empty = True elif line[0] == '#': empty = False temp_file.write(line) temp_file.write(u"\n") else: p = line.split("=") if len(p) != 2: empty = False temp_file.write(line+u"\n") continue key = p[0].strip() value = p[1].strip() # check for modified key/value pairs if key not in done: if (key in self._config and \ self._config[key] != value): empty = False temp_file.write(u'%s=%s\n' % (key, self._config[key])) modified = True elif key in self._deleted: modified = True else: empty = False temp_file.write(line+u"\n") done.append(key) else: modified = True # write remaining key/value pairs if len(self._config) > 0: for (key,value) in self._config.items(): if key in done: continue if key in ["MinimalMark", "AutomaticHelpers"]: # omit deprecated from new config continue if not empty: temp_file.write(u"\n") empty = True temp_file.write(u'%s=%s\n' % (key, value)) modified = True if f: f.close() temp_file.close() if not modified: # not modified: remove tempfile os.remove(temp_file.name) return # make backup if os.path.exists(self.filename): try: shutil.copy2(self.filename, "%s.old" % self.filename) except Exception as msg: os.remove(temp_file.name) raise IOError("Backup of '%s' failed: %s" % (self.filename, msg)) # copy tempfile try: shutil.move(temp_file.name, self.filename) except Exception as msg: os.remove(temp_file.name) raise IOError("Failed to create '%s': %s" % (self.filename, msg)) else: os.chmod(self.filename, 0o600) PKpge[γ11io/lockdown_whitelist.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import xml.sax as sax import os import io import shutil from firewall import config from firewall.core.io.io_object import PY2, IO_Object, \ IO_Object_ContentHandler, IO_Object_XMLGenerator from firewall.core.logger import log from firewall.functions import uniqify, checkUser, checkUid, checkCommand, \ checkContext, u2b_if_py2 from firewall import errors from firewall.errors import FirewallError class lockdown_whitelist_ContentHandler(IO_Object_ContentHandler): def __init__(self, item): IO_Object_ContentHandler.__init__(self, item) self.whitelist = False def startElement(self, name, attrs): IO_Object_ContentHandler.startElement(self, name, attrs) self.item.parser_check_element_attrs(name, attrs) if name == "whitelist": if self.whitelist: raise FirewallError(errors.PARSE_ERROR, "More than one whitelist.") self.whitelist = True elif name == "command": if not self.whitelist: log.error("Parse Error: command outside of whitelist") return command = attrs["name"] self.item.add_command(command) elif name == "user": if not self.whitelist: log.error("Parse Error: user outside of whitelist") return if "id" in attrs: try: uid = int(attrs["id"]) except ValueError: log.error("Parse Error: %s is not a valid uid" % attrs["id"]) return self.item.add_uid(uid) elif "name" in attrs: self.item.add_user(attrs["name"]) elif name == "selinux": if not self.whitelist: log.error("Parse Error: selinux outside of whitelist") return if "context" not in attrs: log.error("Parse Error: no context") return self.item.add_context(attrs["context"]) else: log.error('Unknown XML element %s' % name) return class LockdownWhitelist(IO_Object): """ LockdownWhitelist class """ IMPORT_EXPORT_STRUCTURE = ( ( "commands", [ "" ] ), # as ( "contexts", [ "" ] ), # as ( "users", [ "" ] ), # as ( "uids", [ 0 ] ) # ai ) DBUS_SIGNATURE = '(asasasai)' ADDITIONAL_ALNUM_CHARS = [ "_" ] PARSER_REQUIRED_ELEMENT_ATTRS = { "whitelist": None, "command": [ "name" ], "user": None, # "group": None, "selinux": [ "context" ], } PARSER_OPTIONAL_ELEMENT_ATTRS = { "user": [ "id", "name" ], # "group": [ "id", "name" ], } def __init__(self, filename): super(LockdownWhitelist, self).__init__() self.filename = filename self.parser = None self.commands = [ ] self.contexts = [ ] self.users = [ ] self.uids = [ ] # self.gids = [ ] # self.groups = [ ] def _check_config(self, config, item, all_config): if item in [ "commands", "contexts", "users", "uids" ]: for x in config: self._check_config(x, item[:-1], all_config) elif item == "command": if not checkCommand(config): raise FirewallError(errors.INVALID_COMMAND, config) elif item == "context": if not checkContext(config): raise FirewallError(errors.INVALID_CONTEXT, config) elif item == "user": if not checkUser(config): raise FirewallError(errors.INVALID_USER, config) elif item == "uid": if not checkUid(config): raise FirewallError(errors.INVALID_UID, config) def cleanup(self): del self.commands[:] del self.contexts[:] del self.users[:] del self.uids[:] # del self.gids[:] # del self.groups[:] def encode_strings(self): """ HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.""" self.commands = [ u2b_if_py2(x) for x in self.commands ] self.contexts = [ u2b_if_py2(x) for x in self.contexts ] self.users = [ u2b_if_py2(x) for x in self.users ] # commands def add_command(self, command): if not checkCommand(command): raise FirewallError(errors.INVALID_COMMAND, command) if command not in self.commands: self.commands.append(command) else: raise FirewallError(errors.ALREADY_ENABLED, 'Command "%s" already in whitelist' % command) def remove_command(self, command): if command in self.commands: self.commands.remove(command) else: raise FirewallError(errors.NOT_ENABLED, 'Command "%s" not in whitelist.' % command) def has_command(self, command): return (command in self.commands) def match_command(self, command): for _command in self.commands: if _command.endswith("*"): if command.startswith(_command[:-1]): return True else: if _command == command: return True return False def get_commands(self): return self.commands # user ids def add_uid(self, uid): if not checkUid(uid): raise FirewallError(errors.INVALID_UID, str(uid)) if uid not in self.uids: self.uids.append(uid) else: raise FirewallError(errors.ALREADY_ENABLED, 'Uid "%s" already in whitelist' % uid) def remove_uid(self, uid): if uid in self.uids: self.uids.remove(uid) else: raise FirewallError(errors.NOT_ENABLED, 'Uid "%s" not in whitelist.' % uid) def has_uid(self, uid): return (uid in self.uids) def match_uid(self, uid): return (uid in self.uids) def get_uids(self): return self.uids # users def add_user(self, user): if not checkUser(user): raise FirewallError(errors.INVALID_USER, user) if user not in self.users: self.users.append(user) else: raise FirewallError(errors.ALREADY_ENABLED, 'User "%s" already in whitelist' % user) def remove_user(self, user): if user in self.users: self.users.remove(user) else: raise FirewallError(errors.NOT_ENABLED, 'User "%s" not in whitelist.' % user) def has_user(self, user): return (user in self.users) def match_user(self, user): return (user in self.users) def get_users(self): return self.users # # group ids # # def add_gid(self, gid): # if gid not in self.gids: # self.gids.append(gid) # # def remove_gid(self, gid): # if gid in self.gids: # self.gids.remove(gid) # else: # raise FirewallError(errors.NOT_ENABLED, # 'Gid "%s" not in whitelist.' % gid) # # def has_gid(self, gid): # return (gid in self.gids) # # def match_gid(self, gid): # return (gid in self.gids) # # def get_gids(self): # return self.gids # # groups # # def add_group(self, group): # if group not in self.groups: # self.groups.append(group) # # def remove_group(self, group): # if group in self.groups: # self.groups.remove(group) # else: # raise FirewallError(errors.NOT_ENABLED, # 'Group "%s" not in whitelist.' % group) # # def has_group(self, group): # return (group in self.groups) # # def match_group(self, group): # return (group in self.groups) # # def get_groups(self): # return self.groups # selinux contexts def add_context(self, context): if not checkContext(context): raise FirewallError(errors.INVALID_CONTEXT, context) if context not in self.contexts: self.contexts.append(context) else: raise FirewallError(errors.ALREADY_ENABLED, 'Context "%s" already in whitelist' % context) def remove_context(self, context): if context in self.contexts: self.contexts.remove(context) else: raise FirewallError(errors.NOT_ENABLED, 'Context "%s" not in whitelist.' % context) def has_context(self, context): return (context in self.contexts) def match_context(self, context): return (context in self.contexts) def get_contexts(self): return self.contexts # read and write def read(self): self.cleanup() if not self.filename.endswith(".xml"): raise FirewallError(errors.INVALID_NAME, "'%s' is missing .xml suffix" % self.filename) handler = lockdown_whitelist_ContentHandler(self) parser = sax.make_parser() parser.setContentHandler(handler) try: parser.parse(self.filename) except sax.SAXParseException as msg: raise FirewallError(errors.INVALID_TYPE, "Not a valid file: %s" % \ msg.getException()) del handler del parser if PY2: self.encode_strings() def write(self): if os.path.exists(self.filename): try: shutil.copy2(self.filename, "%s.old" % self.filename) except Exception as msg: raise IOError("Backup of '%s' failed: %s" % (self.filename, msg)) if not os.path.exists(config.ETC_FIREWALLD): os.mkdir(config.ETC_FIREWALLD, 0o750) f = io.open(self.filename, mode='wt', encoding='UTF-8') handler = IO_Object_XMLGenerator(f) handler.startDocument() # start whitelist element handler.startElement("whitelist", { }) handler.ignorableWhitespace("\n") # commands for command in uniqify(self.commands): handler.ignorableWhitespace(" ") handler.simpleElement("command", { "name": command }) handler.ignorableWhitespace("\n") for uid in uniqify(self.uids): handler.ignorableWhitespace(" ") handler.simpleElement("user", { "id": str(uid) }) handler.ignorableWhitespace("\n") for user in uniqify(self.users): handler.ignorableWhitespace(" ") handler.simpleElement("user", { "name": user }) handler.ignorableWhitespace("\n") # for gid in uniqify(self.gids): # handler.ignorableWhitespace(" ") # handler.simpleElement("user", { "id": str(gid) }) # handler.ignorableWhitespace("\n") # for group in uniqify(self.groups): # handler.ignorableWhitespace(" ") # handler.simpleElement("group", { "name": group }) # handler.ignorableWhitespace("\n") for context in uniqify(self.contexts): handler.ignorableWhitespace(" ") handler.simpleElement("selinux", { "context": context }) handler.ignorableWhitespace("\n") # end whitelist element handler.endElement("whitelist") handler.ignorableWhitespace("\n") handler.endDocument() f.close() del handler PKpge[ ϢϢ io/policy.pynu[# -*- coding: utf-8 -*- # # SPDX-License-Identifier: GPL-2.0-or-later __all__ = [ "Policy", "policy_reader", "policy_writer" ] import xml.sax as sax import os import io import shutil from firewall import config from firewall.functions import checkIP, checkIP6 from firewall.functions import uniqify, max_policy_name_len, portStr from firewall.core.base import DEFAULT_POLICY_TARGET, POLICY_TARGETS, DEFAULT_POLICY_PRIORITY from firewall.core.io.io_object import IO_Object, \ IO_Object_ContentHandler, IO_Object_XMLGenerator, check_port, \ check_tcpudp, check_protocol from firewall.core import rich from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError def common_startElement(obj, name, attrs): if name == "short": pass elif name == "description": pass elif name == "service": if obj._rule: if obj._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(obj._rule)) obj._rule_error = True return True obj._rule.element = rich.Rich_Service(attrs["name"]) return True if attrs["name"] not in obj.item.services: obj.item.services.append(attrs["name"]) else: log.warning("Service '%s' already set, ignoring.", attrs["name"]) elif name == "port": if obj._rule: if obj._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(obj._rule)) obj._rule_error = True return True obj._rule.element = rich.Rich_Port(attrs["port"], attrs["protocol"]) return True check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) entry = (portStr(attrs["port"], "-"), attrs["protocol"]) if entry not in obj.item.ports: obj.item.ports.append(entry) else: log.warning("Port '%s/%s' already set, ignoring.", attrs["port"], attrs["protocol"]) elif name == "protocol": if obj._rule: if obj._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(obj._rule)) obj._rule_error = True return True obj._rule.element = rich.Rich_Protocol(attrs["value"]) else: check_protocol(attrs["value"]) if attrs["value"] not in obj.item.protocols: obj.item.protocols.append(attrs["value"]) else: log.warning("Protocol '%s' already set, ignoring.", attrs["value"]) elif name == "icmp-block": if obj._rule: if obj._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(obj._rule)) obj._rule_error = True return True obj._rule.element = rich.Rich_IcmpBlock(attrs["name"]) return True if attrs["name"] not in obj.item.icmp_blocks: obj.item.icmp_blocks.append(attrs["name"]) else: log.warning("icmp-block '%s' already set, ignoring.", attrs["name"]) elif name == "icmp-type": if obj._rule: if obj._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(obj._rule)) obj._rule_error = True return True obj._rule.element = rich.Rich_IcmpType(attrs["name"]) return True else: log.warning("Invalid rule: icmp-block '%s' outside of rule", attrs["name"]) elif name == "masquerade": if obj._rule: if obj._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(obj._rule)) obj._rule_error = True return True obj._rule.element = rich.Rich_Masquerade() else: if obj.item.masquerade: log.warning("Masquerade already set, ignoring.") else: obj.item.masquerade = True elif name == "forward-port": to_port = "" if "to-port" in attrs: to_port = attrs["to-port"] to_addr = "" if "to-addr" in attrs: to_addr = attrs["to-addr"] if obj._rule: if obj._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(obj._rule)) obj._rule_error = True return True obj._rule.element = rich.Rich_ForwardPort(attrs["port"], attrs["protocol"], to_port, to_addr) return True check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) if to_port: check_port(to_port) if to_addr: if not checkIP(to_addr) and not checkIP6(to_addr): raise FirewallError(errors.INVALID_ADDR, "to-addr '%s' is not a valid address" \ % to_addr) entry = (portStr(attrs["port"], "-"), attrs["protocol"], portStr(to_port, "-"), str(to_addr)) if entry not in obj.item.forward_ports: obj.item.forward_ports.append(entry) else: log.warning("Forward port %s/%s%s%s already set, ignoring.", attrs["port"], attrs["protocol"], " >%s" % to_port if to_port else "", " @%s" % to_addr if to_addr else "") elif name == "source-port": if obj._rule: if obj._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(obj._rule)) obj._rule_error = True return True obj._rule.element = rich.Rich_SourcePort(attrs["port"], attrs["protocol"]) return True check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) entry = (portStr(attrs["port"], "-"), attrs["protocol"]) if entry not in obj.item.source_ports: obj.item.source_ports.append(entry) else: log.warning("Source port '%s/%s' already set, ignoring.", attrs["port"], attrs["protocol"]) elif name == "destination": if not obj._rule: log.warning('Invalid rule: Destination outside of rule') obj._rule_error = True return True if obj._rule.destination: log.warning("Invalid rule: More than one destination in rule '%s', ignoring.", str(obj._rule)) return True invert = False address = None if "address" in attrs: address = attrs["address"] ipset = None if "ipset" in attrs: ipset = attrs["ipset"] if "invert" in attrs and \ attrs["invert"].lower() in [ "yes", "true" ]: invert = True obj._rule.destination = rich.Rich_Destination(address, ipset, invert) elif name in [ "accept", "reject", "drop", "mark" ]: if not obj._rule: log.warning('Invalid rule: Action outside of rule') obj._rule_error = True return True if obj._rule.action: log.warning('Invalid rule: More than one action') obj._rule_error = True return True if name == "accept": obj._rule.action = rich.Rich_Accept() elif name == "reject": _type = None if "type" in attrs: _type = attrs["type"] obj._rule.action = rich.Rich_Reject(_type) elif name == "drop": obj._rule.action = rich.Rich_Drop() elif name == "mark": _set = attrs["set"] obj._rule.action = rich.Rich_Mark(_set) obj._limit_ok = obj._rule.action elif name == "log": if not obj._rule: log.warning('Invalid rule: Log outside of rule') return True if obj._rule.log: log.warning('Invalid rule: More than one log') return True level = None if "level" in attrs: level = attrs["level"] if level not in [ "emerg", "alert", "crit", "error", "warning", "notice", "info", "debug" ]: log.warning('Invalid rule: Invalid log level') obj._rule_error = True return True prefix = attrs["prefix"] if "prefix" in attrs else None obj._rule.log = rich.Rich_Log(prefix, level) obj._limit_ok = obj._rule.log elif name == "audit": if not obj._rule: log.warning('Invalid rule: Audit outside of rule') return True if obj._rule.audit: log.warning("Invalid rule: More than one audit in rule '%s', ignoring.", str(obj._rule)) obj._rule_error = True return True obj._rule.audit = rich.Rich_Audit() obj._limit_ok = obj._rule.audit elif name == "rule": family = None priority = 0 if "family" in attrs: family = attrs["family"] if family not in [ "ipv4", "ipv6" ]: log.warning('Invalid rule: Rule family "%s" invalid', attrs["family"]) obj._rule_error = True return True if "priority" in attrs: priority = int(attrs["priority"]) obj._rule = rich.Rich_Rule(family=family, priority=priority) elif name == "limit": if not obj._limit_ok: log.warning('Invalid rule: Limit outside of action, log and audit') obj._rule_error = True return True if obj._limit_ok.limit: log.warning("Invalid rule: More than one limit in rule '%s', ignoring.", str(obj._rule)) obj._rule_error = True return True value = attrs["value"] obj._limit_ok.limit = rich.Rich_Limit(value, attrs.get("burst")) else: return False return True def common_endElement(obj, name): if name == "rule": if not obj._rule_error: try: obj._rule.check() except Exception as e: log.warning("%s: %s", e, str(obj._rule)) else: if str(obj._rule) not in obj.item.rules_str: obj.item.rules.append(obj._rule) obj.item.rules_str.append(str(obj._rule)) else: log.warning("Rule '%s' already set, ignoring.", str(obj._rule)) obj._rule = None obj._rule_error = False elif name in [ "accept", "reject", "drop", "mark", "log", "audit" ]: obj._limit_ok = None def common_check_config(obj, config, item, all_config): obj_type = "Policy" if isinstance(obj, Policy) else "Zone" if item == "services" and obj.fw_config: existing_services = obj.fw_config.get_services() for service in config: if service not in existing_services: raise FirewallError(errors.INVALID_SERVICE, "'%s' not among existing services" % \ service) elif item == "ports": for port in config: check_port(port[0]) check_tcpudp(port[1]) elif item == "protocols": for proto in config: check_protocol(proto) elif item == "icmp_blocks" and obj.fw_config: existing_icmptypes = obj.fw_config.get_icmptypes() for icmptype in config: if icmptype not in existing_icmptypes: raise FirewallError(errors.INVALID_ICMPTYPE, "'%s' not among existing icmp types" % \ icmptype) elif item == "forward_ports": for fwd_port in config: check_port(fwd_port[0]) check_tcpudp(fwd_port[1]) if not fwd_port[2] and not fwd_port[3]: raise FirewallError( errors.INVALID_FORWARD, "'%s' is missing to-port AND to-addr " % fwd_port) if fwd_port[2]: check_port(fwd_port[2]) if fwd_port[3]: if not checkIP(fwd_port[3]) and not checkIP6(fwd_port[3]): raise FirewallError( errors.INVALID_ADDR, "to-addr '%s' is not a valid address" % fwd_port[3]) elif item == "source_ports": for port in config: check_port(port[0]) check_tcpudp(port[1]) elif item in ["rules_str", "rich_rules"]: for rule in config: obj_rich = rich.Rich_Rule(rule_str=rule) if obj.fw_config and obj_rich.element and (isinstance(obj_rich.element, rich.Rich_IcmpBlock) or isinstance(obj_rich.element, rich.Rich_IcmpType)): existing_icmptypes = obj.fw_config.get_icmptypes() if obj_rich.element.name not in existing_icmptypes: raise FirewallError(errors.INVALID_ICMPTYPE, "'%s' not among existing icmp types" % \ obj_rich.element.name) elif obj_rich.family: ict = obj.fw_config.get_icmptype(obj_rich.element.name) if ict.destination and obj_rich.family not in ict.destination: raise FirewallError(errors.INVALID_ICMPTYPE, "rich rule family '%s' conflicts with icmp type '%s'" % \ (obj_rich.family, obj_rich.element.name)) elif obj.fw_config and isinstance(obj_rich.element, rich.Rich_Service): existing_services = obj.fw_config.get_services() if obj_rich.element.name not in existing_services: raise FirewallError( errors.INVALID_SERVICE, "{} '{}': '{}' not among existing services".format( obj_type, obj.name, obj_rich.element.name ), ) def _handler_add_rich_limit(handler, limit): d = {"value": limit.value} burst = limit.burst if burst is not None: d["burst"] = burst handler.simpleElement("limit", d) def common_writer(obj, handler): # short if obj.short and obj.short != "": handler.ignorableWhitespace(" ") handler.startElement("short", { }) handler.characters(obj.short) handler.endElement("short") handler.ignorableWhitespace("\n") # description if obj.description and obj.description != "": handler.ignorableWhitespace(" ") handler.startElement("description", { }) handler.characters(obj.description) handler.endElement("description") handler.ignorableWhitespace("\n") # services for service in uniqify(obj.services): handler.ignorableWhitespace(" ") handler.simpleElement("service", { "name": service }) handler.ignorableWhitespace("\n") # ports for port in uniqify(obj.ports): handler.ignorableWhitespace(" ") handler.simpleElement("port", { "port": port[0], "protocol": port[1] }) handler.ignorableWhitespace("\n") # protocols for protocol in uniqify(obj.protocols): handler.ignorableWhitespace(" ") handler.simpleElement("protocol", { "value": protocol }) handler.ignorableWhitespace("\n") # icmp-blocks for icmp in uniqify(obj.icmp_blocks): handler.ignorableWhitespace(" ") handler.simpleElement("icmp-block", { "name": icmp }) handler.ignorableWhitespace("\n") # masquerade if obj.masquerade: handler.ignorableWhitespace(" ") handler.simpleElement("masquerade", { }) handler.ignorableWhitespace("\n") # forward-ports for forward in uniqify(obj.forward_ports): handler.ignorableWhitespace(" ") attrs = { "port": forward[0], "protocol": forward[1] } if forward[2] and forward[2] != "" : attrs["to-port"] = forward[2] if forward[3] and forward[3] != "" : attrs["to-addr"] = forward[3] handler.simpleElement("forward-port", attrs) handler.ignorableWhitespace("\n") # source-ports for port in uniqify(obj.source_ports): handler.ignorableWhitespace(" ") handler.simpleElement("source-port", { "port": port[0], "protocol": port[1] }) handler.ignorableWhitespace("\n") # rules for rule in obj.rules: attrs = { } if rule.family: attrs["family"] = rule.family if rule.priority != 0: attrs["priority"] = str(rule.priority) handler.ignorableWhitespace(" ") handler.startElement("rule", attrs) handler.ignorableWhitespace("\n") # source if rule.source: attrs = { } if rule.source.addr: attrs["address"] = rule.source.addr if rule.source.mac: attrs["mac"] = rule.source.mac if rule.source.ipset: attrs["ipset"] = rule.source.ipset if rule.source.invert: attrs["invert"] = "True" handler.ignorableWhitespace(" ") handler.simpleElement("source", attrs) handler.ignorableWhitespace("\n") # destination if rule.destination: attrs = { } if rule.destination.addr: attrs["address"] = rule.destination.addr if rule.destination.ipset: attrs["ipset"] = rule.destination.ipset if rule.destination.invert: attrs["invert"] = "True" handler.ignorableWhitespace(" ") handler.simpleElement("destination", attrs) handler.ignorableWhitespace("\n") # element if rule.element: element = "" attrs = { } if type(rule.element) == rich.Rich_Service: element = "service" attrs["name"] = rule.element.name elif type(rule.element) == rich.Rich_Port: element = "port" attrs["port"] = rule.element.port attrs["protocol"] = rule.element.protocol elif type(rule.element) == rich.Rich_Protocol: element = "protocol" attrs["value"] = rule.element.value elif type(rule.element) == rich.Rich_Masquerade: element = "masquerade" elif type(rule.element) == rich.Rich_IcmpBlock: element = "icmp-block" attrs["name"] = rule.element.name elif type(rule.element) == rich.Rich_IcmpType: element = "icmp-type" attrs["name"] = rule.element.name elif type(rule.element) == rich.Rich_ForwardPort: element = "forward-port" attrs["port"] = rule.element.port attrs["protocol"] = rule.element.protocol if rule.element.to_port != "": attrs["to-port"] = rule.element.to_port if rule.element.to_address != "": attrs["to-addr"] = rule.element.to_address elif type(rule.element) == rich.Rich_SourcePort: element = "source-port" attrs["port"] = rule.element.port attrs["protocol"] = rule.element.protocol else: raise FirewallError( errors.INVALID_OBJECT, "Unknown element '%s' in obj_writer" % type(rule.element)) handler.ignorableWhitespace(" ") handler.simpleElement(element, attrs) handler.ignorableWhitespace("\n") # rule.element # log if rule.log: attrs = { } if rule.log.prefix: attrs["prefix"] = rule.log.prefix if rule.log.level: attrs["level"] = rule.log.level if rule.log.limit: handler.ignorableWhitespace(" ") handler.startElement("log", attrs) handler.ignorableWhitespace("\n ") _handler_add_rich_limit(handler, rule.log.limit) handler.ignorableWhitespace("\n ") handler.endElement("log") else: handler.ignorableWhitespace(" ") handler.simpleElement("log", attrs) handler.ignorableWhitespace("\n") # audit if rule.audit: attrs = {} if rule.audit.limit: handler.ignorableWhitespace(" ") handler.startElement("audit", { }) handler.ignorableWhitespace("\n ") _handler_add_rich_limit(handler, rule.audit.limit) handler.ignorableWhitespace("\n ") handler.endElement("audit") else: handler.ignorableWhitespace(" ") handler.simpleElement("audit", attrs) handler.ignorableWhitespace("\n") # action if rule.action: action = "" attrs = { } if type(rule.action) == rich.Rich_Accept: action = "accept" elif type(rule.action) == rich.Rich_Reject: action = "reject" if rule.action.type: attrs["type"] = rule.action.type elif type(rule.action) == rich.Rich_Drop: action = "drop" elif type(rule.action) == rich.Rich_Mark: action = "mark" attrs["set"] = rule.action.set else: log.warning("Unknown action '%s'", type(rule.action)) if rule.action.limit: handler.ignorableWhitespace(" ") handler.startElement(action, attrs) handler.ignorableWhitespace("\n ") _handler_add_rich_limit(handler, rule.action.limit) handler.ignorableWhitespace("\n ") handler.endElement(action) else: handler.ignorableWhitespace(" ") handler.simpleElement(action, attrs) handler.ignorableWhitespace("\n") handler.ignorableWhitespace(" ") handler.endElement("rule") handler.ignorableWhitespace("\n") class Policy(IO_Object): priority_min = -32768 priority_max = 32767 priority_default = DEFAULT_POLICY_PRIORITY priority_reserved = [0] IMPORT_EXPORT_STRUCTURE = ( ( "version", "" ), # s ( "short", "" ), # s ( "description", "" ), # s ( "target", "" ), # s ( "services", [ "", ], ), # as ( "ports", [ ( "", "" ), ], ), # a(ss) ( "icmp_blocks", [ "", ], ), # as ( "masquerade", False ), # b ( "forward_ports", [ ( "", "", "", "" ), ], ), # a(ssss) ( "rich_rules", [ "" ] ), # as ( "protocols", [ "", ], ), # as ( "source_ports", [ ( "", "" ), ], ), # a(ss) ( "priority", 0 ), # i ( "ingress_zones", [ "" ] ), # as ( "egress_zones", [ "" ] ), # as ) ADDITIONAL_ALNUM_CHARS = [ "_", "-", "/" ] PARSER_REQUIRED_ELEMENT_ATTRS = { "short": None, "description": None, "policy": ["target"], "service": [ "name" ], "port": [ "port", "protocol" ], "icmp-block": [ "name" ], "icmp-type": [ "name" ], "masquerade": None, "forward-port": [ "port", "protocol" ], "rule": None, "source": None, "destination": None, "protocol": [ "value" ], "source-port": [ "port", "protocol" ], "log": None, "audit": None, "accept": None, "reject": None, "drop": None, "mark": [ "set" ], "limit": [ "value" ], "ingress-zone": [ "name" ], "egress-zone": [ "name" ], } PARSER_OPTIONAL_ELEMENT_ATTRS = { "policy": [ "version", "priority" ], "forward-port": [ "to-port", "to-addr" ], "rule": [ "family", "priority" ], "source": [ "address", "mac", "invert", "family", "ipset" ], "destination": [ "address", "invert", "ipset" ], "log": [ "prefix", "level" ], "reject": [ "type" ], "limit": ["burst"], } def __init__(self): super(Policy, self).__init__() self.version = "" self.short = "" self.description = "" self.target = DEFAULT_POLICY_TARGET self.services = [ ] self.ports = [ ] self.protocols = [ ] self.icmp_blocks = [ ] self.masquerade = False self.forward_ports = [ ] self.source_ports = [ ] self.fw_config = None # to be able to check services and a icmp_blocks self.rules = [ ] self.rules_str = [ ] self.applied = False self.priority = self.priority_default self.derived_from_zone = None self.ingress_zones = [] self.egress_zones = [] def cleanup(self): self.version = "" self.short = "" self.description = "" self.target = DEFAULT_POLICY_TARGET del self.services[:] del self.ports[:] del self.protocols[:] del self.icmp_blocks[:] self.masquerade = False del self.forward_ports[:] del self.source_ports[:] self.fw_config = None # to be able to check services and a icmp_blocks del self.rules[:] del self.rules_str[:] self.applied = False self.priority = self.priority_default del self.ingress_zones[:] del self.egress_zones[:] def __getattr__(self, name): if name == "rich_rules": return self.rules_str else: return getattr(super(Policy, self), name) def __setattr__(self, name, value): if name == "rich_rules": self.rules = [rich.Rich_Rule(rule_str=s) for s in value] # must convert back to string to get the canonical string. self.rules_str = [str(s) for s in self.rules] else: super(Policy, self).__setattr__(name, value) def _check_config(self, config, item, all_config): common_check_config(self, config, item, all_config) if item == "target": if config not in POLICY_TARGETS: raise FirewallError(errors.INVALID_TARGET, "'%s' is invalid target" % (config)) elif item == "priority": if config in self.priority_reserved or \ config > self.priority_max or \ config < self.priority_min: raise FirewallError(errors.INVALID_PRIORITY, "%d is invalid priority. Must be in range [%d, %d]. The following are reserved: %s" % (config, self.priority_min, self.priority_max, self.priority_reserved)) elif item in ["ingress_zones", "egress_zones"]: existing_zones = ["ANY", "HOST"] if self.fw_config: existing_zones += self.fw_config.get_zones() for zone in config: if zone not in existing_zones: raise FirewallError(errors.INVALID_ZONE, "'%s' not among existing zones" % (zone)) if ((zone not in ["ANY", "HOST"] and (set(["ANY", "HOST"]) & set(config))) or \ (zone in ["ANY", "HOST"] and (set(config) - set([zone])))): raise FirewallError(errors.INVALID_ZONE, "'%s' may only contain one of: many regular zones, ANY, or HOST" % (item)) if zone == "HOST" and \ ((item == "ingress_zones" and "egress_zones" in all_config and "HOST" in all_config["egress_zones"]) or \ (item == "egress_zones" and "ingress_zones" in all_config and "HOST" in all_config["ingress_zones"])): raise FirewallError(errors.INVALID_ZONE, "'HOST' can only appear in either ingress or egress zones, but not both") elif item == "masquerade" and config: if "egress_zones" in all_config and "HOST" in all_config["egress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for egress zone 'HOST'") elif "ingress_zones" in all_config: if "HOST" in all_config["ingress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for ingress zone 'HOST'") for zone in all_config["ingress_zones"]: if zone == "ANY": continue z_obj = self.fw_config.get_zone(zone) if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(z_obj): raise FirewallError(errors.INVALID_ZONE, "'masquerade' cannot be used in a policy if an ingress zone has assigned interfaces") elif item == "rich_rules": for rule in config: obj = rich.Rich_Rule(rule_str=rule) if obj.element and isinstance(obj.element, rich.Rich_Masquerade): if "egress_zones" in all_config and "HOST" in all_config["egress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for egress zone 'HOST'") elif "ingress_zones" in all_config: if "HOST" in all_config["ingress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'masquerade' is invalid for ingress zone 'HOST'") for zone in all_config["ingress_zones"]: if zone == "ANY": continue z_obj = self.fw_config.get_zone(zone) if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(z_obj): raise FirewallError(errors.INVALID_ZONE, "'masquerade' cannot be used in a policy if an ingress zone has assigned interfaces") elif obj.element and isinstance(obj.element, rich.Rich_ForwardPort): if "egress_zones" in all_config: if "HOST" in all_config["egress_zones"]: if obj.element.to_address: raise FirewallError(errors.INVALID_FORWARD, "A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'") elif all_config["egress_zones"]: if not obj.element.to_address: raise FirewallError(errors.INVALID_FORWARD, "'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone") if "ANY" not in all_config["egress_zones"]: for zone in all_config["egress_zones"]: z_obj = self.fw_config.get_zone(zone) if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(z_obj): raise FirewallError(errors.INVALID_ZONE, "'forward-port' cannot be used in a policy if an egress zone has assigned interfaces") elif obj.action and isinstance(obj.action, rich.Rich_Mark): if "egress_zones" in all_config: for zone in all_config["egress_zones"]: if zone in ["ANY", "HOST"]: continue z_obj = self.fw_config.get_zone(zone) if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(z_obj): raise FirewallError(errors.INVALID_ZONE, "'mark' action cannot be used in a policy if an egress zone has assigned interfaces") elif item == "forward_ports": for fwd_port in config: if "ingress_zones" in all_config and "HOST" in all_config["ingress_zones"]: raise FirewallError(errors.INVALID_ZONE, "'forward-port' is invalid for ingress zone 'HOST'") elif "egress_zones" in all_config: if "HOST" in all_config["egress_zones"]: if fwd_port[3]: raise FirewallError(errors.INVALID_FORWARD, "A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'") elif all_config["egress_zones"]: if not fwd_port[3]: raise FirewallError(errors.INVALID_FORWARD, "'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone") if "ANY" not in all_config["egress_zones"]: for zone in all_config["egress_zones"]: z_obj = self.fw_config.get_zone(zone) if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(z_obj): raise FirewallError(errors.INVALID_ZONE, "'forward-port' cannot be used in a policy if an egress zone has assigned interfaces") def check_name(self, name): super(Policy, self).check_name(name) if name.startswith('/'): raise FirewallError(errors.INVALID_NAME, "'%s' can't start with '/'" % name) elif name.endswith('/'): raise FirewallError(errors.INVALID_NAME, "'%s' can't end with '/'" % name) elif name.count('/') > 1: raise FirewallError(errors.INVALID_NAME, "more than one '/' in '%s'" % name) else: if "/" in name: checked_name = name[:name.find('/')] else: checked_name = name if len(checked_name) > max_policy_name_len(): raise FirewallError(errors.INVALID_NAME, "Policy of '%s' has %d chars, max is %d" % ( name, len(checked_name), max_policy_name_len())) if self.fw_config: if checked_name in self.fw_config.get_zones(): raise FirewallError(errors.NAME_CONFLICT, "Policies can't have the same name as a zone.") # PARSER class policy_ContentHandler(IO_Object_ContentHandler): def __init__(self, item): IO_Object_ContentHandler.__init__(self, item) self._rule = None self._rule_error = False self._limit_ok = None def startElement(self, name, attrs): IO_Object_ContentHandler.startElement(self, name, attrs) if self._rule_error: return self.item.parser_check_element_attrs(name, attrs) if common_startElement(self, name, attrs): return elif name == "policy": if "version" in attrs: self.item.version = attrs["version"] if "priority" in attrs: self.item.priority = int(attrs["priority"]) if "target" in attrs: target = attrs["target"] if target not in POLICY_TARGETS: raise FirewallError(errors.INVALID_TARGET, target) if target: self.item.target = target elif name == "ingress-zone": if attrs["name"] not in self.item.ingress_zones: self.item.ingress_zones.append(attrs["name"]) else: log.warning("Ingress zone '%s' already set, ignoring.", attrs["name"]) elif name == "egress-zone": if attrs["name"] not in self.item.egress_zones: self.item.egress_zones.append(attrs["name"]) else: log.warning("Egress zone '%s' already set, ignoring.", attrs["name"]) elif name == "source": if not self._rule: log.warning('Invalid rule: Source outside of rule') self._rule_error = True return if self._rule.source: log.warning("Invalid rule: More than one source in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return invert = False if "invert" in attrs and \ attrs["invert"].lower() in [ "yes", "true" ]: invert = True addr = mac = ipset = None if "address" in attrs: addr = attrs["address"] if "mac" in attrs: mac = attrs["mac"] if "ipset" in attrs: ipset = attrs["ipset"] self._rule.source = rich.Rich_Source(addr, mac, ipset, invert=invert) return else: log.warning("Unknown XML element '%s'", name) return def endElement(self, name): IO_Object_ContentHandler.endElement(self, name) common_endElement(self, name) def policy_reader(filename, path, no_check_name=False): policy = Policy() if not filename.endswith(".xml"): raise FirewallError(errors.INVALID_NAME, "'%s' is missing .xml suffix" % filename) policy.name = filename[:-4] if not no_check_name: policy.check_name(policy.name) policy.filename = filename policy.path = path policy.builtin = False if path.startswith(config.ETC_FIREWALLD) else True policy.default = policy.builtin handler = policy_ContentHandler(policy) parser = sax.make_parser() parser.setContentHandler(handler) name = "%s/%s" % (path, filename) with open(name, "rb") as f: source = sax.InputSource(None) source.setByteStream(f) try: parser.parse(source) except sax.SAXParseException as msg: raise FirewallError(errors.INVALID_POLICY, "not a valid policy file: %s" % \ msg.getException()) del handler del parser return policy def policy_writer(policy, path=None): _path = path if path else policy.path if policy.filename: name = "%s/%s" % (_path, policy.filename) else: name = "%s/%s.xml" % (_path, policy.name) if os.path.exists(name): try: shutil.copy2(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) dirpath = os.path.dirname(name) if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath): if not os.path.exists(config.ETC_FIREWALLD): os.mkdir(config.ETC_FIREWALLD, 0o750) os.mkdir(dirpath, 0o750) f = io.open(name, mode='wt', encoding='UTF-8') handler = IO_Object_XMLGenerator(f) handler.startDocument() # start policy element attrs = {} if policy.version and policy.version != "": attrs["version"] = policy.version if policy.priority != policy.priority_default: attrs["priority"] = str(policy.priority) attrs["target"] = policy.target handler.startElement("policy", attrs) handler.ignorableWhitespace("\n") common_writer(policy, handler) # ingress-zones for zone in uniqify(policy.ingress_zones): handler.ignorableWhitespace(" ") handler.simpleElement("ingress-zone", { "name": zone }) handler.ignorableWhitespace("\n") # egress-zones for zone in uniqify(policy.egress_zones): handler.ignorableWhitespace(" ") handler.simpleElement("egress-zone", { "name": zone }) handler.ignorableWhitespace("\n") # end policy element handler.endElement("policy") handler.ignorableWhitespace("\n") handler.endDocument() f.close() del handler PKpge[(55io/io_object.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """Generic io_object handler, io specific check methods.""" __all__ = [ "PY2", "IO_Object", "IO_Object_ContentHandler", "IO_Object_XMLGenerator", "check_port", "check_tcpudp", "check_protocol", "check_address" ] import xml.sax as sax import xml.sax.saxutils as saxutils import copy import sys from collections import OrderedDict from firewall import functions from firewall.functions import b2u from firewall import errors from firewall.errors import FirewallError PY2 = sys.version < '3' class IO_Object(object): """ Abstract IO_Object as base for icmptype, service and zone """ IMPORT_EXPORT_STRUCTURE = ( ) DBUS_SIGNATURE = '()' ADDITIONAL_ALNUM_CHARS = [ ] # additional to alnum PARSER_REQUIRED_ELEMENT_ATTRS = { } PARSER_OPTIONAL_ELEMENT_ATTRS = { } def __init__(self): self.filename = "" self.path = "" self.name = "" self.default = False self.builtin = False def export_config(self): ret = [ ] for x in self.IMPORT_EXPORT_STRUCTURE: ret.append(copy.deepcopy(getattr(self, x[0]))) return tuple(ret) def export_config_dict(self): conf = {} type_formats = dict([(x[0], x[1]) for x in self.IMPORT_EXPORT_STRUCTURE]) for key in type_formats: if getattr(self, key) or isinstance(getattr(self, key), bool): conf[key] = copy.deepcopy(getattr(self, key)) return conf def import_config(self, conf): self.check_config(conf) for i,(element,dummy) in enumerate(self.IMPORT_EXPORT_STRUCTURE): if isinstance(conf[i], list): # remove duplicates without changing the order _conf = [ ] _set = set() for x in conf[i]: if x not in _set: _conf.append(x) _set.add(x) del _set setattr(self, element, copy.deepcopy(_conf)) else: setattr(self, element, copy.deepcopy(conf[i])) def import_config_dict(self, conf): self.check_config_dict(conf) for key in conf: if not hasattr(self, key): raise FirewallError(errors.UNKNOWN_ERROR, "Internal error. '{}' is not a valid attribute".format(key)) if isinstance(conf[key], list): # maintain list order while removing duplicates setattr(self, key, list(OrderedDict.fromkeys(copy.deepcopy(conf[key])))) else: setattr(self, key, copy.deepcopy(conf[key])) def check_name(self, name): if not isinstance(name, str): raise FirewallError(errors.INVALID_TYPE, "'%s' not of type %s, but %s" % (name, type(""), type(name))) if len(name) < 1: raise FirewallError(errors.INVALID_NAME, "name can't be empty") for char in name: if not char.isalnum() and char not in self.ADDITIONAL_ALNUM_CHARS: raise FirewallError( errors.INVALID_NAME, "'%s' is not allowed in '%s'" % ((char, name))) def check_config(self, conf): if len(conf) != len(self.IMPORT_EXPORT_STRUCTURE): raise FirewallError( errors.INVALID_TYPE, "structure size mismatch %d != %d" % \ (len(conf), len(self.IMPORT_EXPORT_STRUCTURE))) conf_dict = {} for i,(x,y) in enumerate(self.IMPORT_EXPORT_STRUCTURE): conf_dict[x] = conf[i] self.check_config_dict(conf_dict) def check_config_dict(self, conf): type_formats = dict([(x[0], x[1]) for x in self.IMPORT_EXPORT_STRUCTURE]) for key in conf: if key not in [x for (x,y) in self.IMPORT_EXPORT_STRUCTURE]: raise FirewallError(errors.INVALID_OPTION, "option '{}' is not valid".format(key)) self._check_config_structure(conf[key], type_formats[key]) self._check_config(conf[key], key, conf) def _check_config(self, dummy1, dummy2, dummy3): # to be overloaded by sub classes return def _check_config_structure(self, conf, structure): if not isinstance(conf, type(structure)): raise FirewallError(errors.INVALID_TYPE, "'%s' not of type %s, but %s" % \ (conf, type(structure), type(conf))) if isinstance(structure, list): # same type elements, else struct if len(structure) != 1: raise FirewallError(errors.INVALID_TYPE, "len('%s') != 1" % structure) for x in conf: self._check_config_structure(x, structure[0]) elif isinstance(structure, tuple): if len(structure) != len(conf): raise FirewallError(errors.INVALID_TYPE, "len('%s') != %d" % (conf, len(structure))) for i,value in enumerate(structure): self._check_config_structure(conf[i], value) elif isinstance(structure, dict): # only one key value pair in structure (skey, svalue) = list(structure.items())[0] for (key, value) in conf.items(): if not isinstance(key, type(skey)): raise FirewallError(errors.INVALID_TYPE, "'%s' not of type %s, but %s" % (\ key, type(skey), type(key))) if not isinstance(value, type(svalue)): raise FirewallError(errors.INVALID_TYPE, "'%s' not of type %s, but %s" % (\ value, type(svalue), type(value))) # check required elements and attributes and also optional attributes def parser_check_element_attrs(self, name, attrs): _attrs = attrs.getNames() found = False if name in self.PARSER_REQUIRED_ELEMENT_ATTRS: found = True if self.PARSER_REQUIRED_ELEMENT_ATTRS[name] is not None: for x in self.PARSER_REQUIRED_ELEMENT_ATTRS[name]: if x in _attrs: _attrs.remove(x) else: raise FirewallError( errors.PARSE_ERROR, "Missing attribute %s for %s" % (x, name)) if name in self.PARSER_OPTIONAL_ELEMENT_ATTRS: found = True for x in self.PARSER_OPTIONAL_ELEMENT_ATTRS[name]: if x in _attrs: _attrs.remove(x) if not found: raise FirewallError(errors.PARSE_ERROR, "Unexpected element %s" % name) # raise attributes[0] for x in _attrs: raise FirewallError(errors.PARSE_ERROR, "%s: Unexpected attribute %s" % (name, x)) # PARSER class UnexpectedElementError(Exception): def __init__(self, name): super(UnexpectedElementError, self).__init__() self.name = name def __str__(self): return "Unexpected element '%s'" % (self.name) class MissingAttributeError(Exception): def __init__(self, name, attribute): super(MissingAttributeError, self).__init__() self.name = name self.attribute = attribute def __str__(self): return "Element '%s': missing '%s' attribute" % \ (self.name, self.attribute) class UnexpectedAttributeError(Exception): def __init__(self, name, attribute): super(UnexpectedAttributeError, self).__init__() self.name = name self.attribute = attribute def __str__(self): return "Element '%s': unexpected attribute '%s'" % \ (self.name, self.attribute) class IO_Object_ContentHandler(sax.handler.ContentHandler): def __init__(self, item): self.item = item self._element = "" def startDocument(self): self._element = "" def startElement(self, name, attrs): self._element = "" def endElement(self, name): if name == "short": self.item.short = self._element elif name == "description": self.item.description = self._element def characters(self, content): self._element += content.replace('\n', ' ') class IO_Object_XMLGenerator(saxutils.XMLGenerator): def __init__(self, out): # fix memory leak in saxutils.XMLGenerator.__init__: # out = _gettextwriter(out, encoding) # creates unbound object results in garbage in gc # # saxutils.XMLGenerator.__init__(self, out, "utf-8") # replaced by modified saxutils.XMLGenerator.__init__ code: sax.handler.ContentHandler.__init__(self) self._write = out.write self._flush = out.flush self._ns_contexts = [{}] # contains uri -> prefix dicts self._current_context = self._ns_contexts[-1] self._undeclared_ns_maps = [] self._encoding = "utf-8" self._pending_start_element = False self._short_empty_elements = False def startElement(self, name, attrs): """ saxutils.XMLGenerator.startElement() expects name and attrs to be unicode and bad things happen if any of them is (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. """ if PY2: attrs = { b2u(name):b2u(value) for name, value in attrs.items() } saxutils.XMLGenerator.startElement(self, name, attrs) def simpleElement(self, name, attrs): """ slightly modified startElement() """ if PY2: self._write(u'<' + b2u(name)) for (name, value) in attrs.items(): self._write(u' %s=%s' % (b2u(name), saxutils.quoteattr(b2u(value)))) self._write(u'/>') else: self._write('<' + name) for (name, value) in attrs.items(): self._write(' %s=%s' % (name, saxutils.quoteattr(value))) self._write('/>') def endElement(self, name): """ saxutils.XMLGenerator.endElement() expects name to be unicode and bad things happen if it's (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. """ saxutils.XMLGenerator.endElement(self, b2u(name)) def characters(self, content): """ saxutils.XMLGenerator.characters() expects content to be unicode and bad things happen if it's (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. """ saxutils.XMLGenerator.characters(self, b2u(content)) def ignorableWhitespace(self, content): """ saxutils.XMLGenerator.ignorableWhitespace() expects content to be unicode and bad things happen if it's (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. """ saxutils.XMLGenerator.ignorableWhitespace(self, b2u(content)) def check_port(port): port_range = functions.getPortRange(port) if port_range == -2: raise FirewallError(errors.INVALID_PORT, "port number in '%s' is too big" % port) elif port_range == -1: raise FirewallError(errors.INVALID_PORT, "'%s' is invalid port range" % port) elif port_range is None: raise FirewallError(errors.INVALID_PORT, "port range '%s' is ambiguous" % port) elif len(port_range) == 2 and port_range[0] >= port_range[1]: raise FirewallError(errors.INVALID_PORT, "'%s' is invalid port range" % port) def check_tcpudp(protocol): if protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, "'%s' not from {'tcp'|'udp'|'sctp'|'dccp'}" % \ protocol) def check_protocol(protocol): if not functions.checkProtocol(protocol): raise FirewallError(errors.INVALID_PROTOCOL, protocol) def check_address(ipv, addr): if not functions.check_address(ipv, addr): raise FirewallError(errors.INVALID_ADDR, "'%s' is not valid %s address" % (addr, ipv)) PKpge[DžRR io/ipset.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2015-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """ipset io XML handler, reader, writer""" __all__ = [ "IPSet", "ipset_reader", "ipset_writer" ] import xml.sax as sax import os import io import shutil from firewall import config from firewall.functions import checkIP, checkIP6, checkIPnMask, \ checkIP6nMask, u2b_if_py2, check_mac, check_port, checkInterface, \ checkProtocol from firewall.core.io.io_object import PY2, IO_Object, \ IO_Object_ContentHandler, IO_Object_XMLGenerator from firewall.core.ipset import IPSET_TYPES, IPSET_CREATE_OPTIONS from firewall.core.icmp import check_icmp_name, check_icmp_type, \ check_icmpv6_name, check_icmpv6_type from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError class IPSet(IO_Object): IMPORT_EXPORT_STRUCTURE = ( ( "version", "" ), # s ( "short", "" ), # s ( "description", "" ), # s ( "type", "" ), # s ( "options", { "": "", }, ), # a{ss} ( "entries", [ "" ], ), # as ) DBUS_SIGNATURE = '(ssssa{ss}as)' ADDITIONAL_ALNUM_CHARS = [ "_", "-", ":", "." ] PARSER_REQUIRED_ELEMENT_ATTRS = { "short": None, "description": None, "ipset": [ "type" ], "option": [ "name" ], "entry": None, } PARSER_OPTIONAL_ELEMENT_ATTRS = { "ipset": [ "version" ], "option": [ "value" ], } def __init__(self): super(IPSet, self).__init__() self.version = "" self.short = "" self.description = "" self.type = "" self.entries = [ ] self.options = { } self.applied = False def cleanup(self): self.version = "" self.short = "" self.description = "" self.type = "" del self.entries[:] self.options.clear() self.applied = False def encode_strings(self): """ HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.""" self.version = u2b_if_py2(self.version) self.short = u2b_if_py2(self.short) self.description = u2b_if_py2(self.description) self.type = u2b_if_py2(self.type) self.options = { u2b_if_py2(k):u2b_if_py2(v) for k, v in self.options.items() } self.entries = [ u2b_if_py2(e) for e in self.entries ] @staticmethod def check_entry(entry, options, ipset_type): family = "ipv4" if "family" in options: if options["family"] == "inet6": family = "ipv6" if not ipset_type.startswith("hash:"): raise FirewallError(errors.INVALID_IPSET, "ipset type '%s' not usable" % ipset_type) flags = ipset_type[5:].split(",") items = entry.split(",") if len(flags) != len(items) or len(flags) < 1: raise FirewallError( errors.INVALID_ENTRY, "entry '%s' does not match ipset type '%s'" % \ (entry, ipset_type)) for i in range(len(flags)): flag = flags[i] item = items[i] if flag == "ip": if "-" in item and family == "ipv4": # IP ranges only with plain IPs, no masks if i > 1: raise FirewallError( errors.INVALID_ENTRY, "invalid address '%s' in '%s'[%d]" % \ (item, entry, i)) splits = item.split("-") if len(splits) != 2: raise FirewallError( errors.INVALID_ENTRY, "invalid address range '%s' in '%s' for %s (%s)" % \ (item, entry, ipset_type, family)) for _split in splits: if (family == "ipv4" and not checkIP(_split)) or \ (family == "ipv6" and not checkIP6(_split)): raise FirewallError( errors.INVALID_ENTRY, "invalid address '%s' in '%s' for %s (%s)" % \ (_split, entry, ipset_type, family)) else: # IPs with mask only allowed in the first # position of the type if family == "ipv4": if item == "0.0.0.0": raise FirewallError( errors.INVALID_ENTRY, "invalid address '%s' in '%s' for %s (%s)" % \ (item, entry, ipset_type, family)) if i == 0: ip_check = checkIPnMask else: ip_check = checkIP else: ip_check = checkIP6 if not ip_check(item): raise FirewallError( errors.INVALID_ENTRY, "invalid address '%s' in '%s' for %s (%s)" % \ (item, entry, ipset_type, family)) elif flag == "net": if "-" in item: # IP ranges only with plain IPs, no masks splits = item.split("-") if len(splits) != 2: raise FirewallError( errors.INVALID_ENTRY, "invalid address range '%s' in '%s' for %s (%s)" % \ (item, entry, ipset_type, family)) # First part can only be a plain IP if (family == "ipv4" and not checkIP(splits[0])) or \ (family == "ipv6" and not checkIP6(splits[0])): raise FirewallError( errors.INVALID_ENTRY, "invalid address '%s' in '%s' for %s (%s)" % \ (splits[0], entry, ipset_type, family)) # Second part can also have a mask if (family == "ipv4" and not checkIPnMask(splits[1])) or \ (family == "ipv6" and not checkIP6nMask(splits[1])): raise FirewallError( errors.INVALID_ENTRY, "invalid address '%s' in '%s' for %s (%s)" % \ (splits[1], entry, ipset_type, family)) else: # IPs with mask allowed in all positions, but no /0 if item.endswith("/0"): if not (family == "ipv6" and i == 0 and ipset_type == "hash:net,iface"): raise FirewallError( errors.INVALID_ENTRY, "invalid address '%s' in '%s' for %s (%s)" % \ (item, entry, ipset_type, family)) if (family == "ipv4" and not checkIPnMask(item)) or \ (family == "ipv6" and not checkIP6nMask(item)): raise FirewallError( errors.INVALID_ENTRY, "invalid address '%s' in '%s' for %s (%s)" % \ (item, entry, ipset_type, family)) elif flag == "mac": # ipset does not allow to add 00:00:00:00:00:00 if not check_mac(item) or item == "00:00:00:00:00:00": raise FirewallError( errors.INVALID_ENTRY, "invalid mac address '%s' in '%s'" % (item, entry)) elif flag == "port": if ":" in item: splits = item.split(":") if len(splits) != 2: raise FirewallError( errors.INVALID_ENTRY, "invalid port '%s'" % (item)) if splits[0] == "icmp": if family != "ipv4": raise FirewallError( errors.INVALID_ENTRY, "invalid protocol for family '%s' in '%s'" % \ (family, entry)) if not check_icmp_name(splits[1]) and not \ check_icmp_type(splits[1]): raise FirewallError( errors.INVALID_ENTRY, "invalid icmp type '%s' in '%s'" % \ (splits[1], entry)) elif splits[0] in [ "icmpv6", "ipv6-icmp" ]: if family != "ipv6": raise FirewallError( errors.INVALID_ENTRY, "invalid protocol for family '%s' in '%s'" % \ (family, entry)) if not check_icmpv6_name(splits[1]) and not \ check_icmpv6_type(splits[1]): raise FirewallError( errors.INVALID_ENTRY, "invalid icmpv6 type '%s' in '%s'" % \ (splits[1], entry)) elif splits[0] not in [ "tcp", "sctp", "udp", "udplite" ] \ and not checkProtocol(splits[0]): raise FirewallError( errors.INVALID_ENTRY, "invalid protocol '%s' in '%s'" % (splits[0], entry)) elif not check_port(splits[1]): raise FirewallError( errors.INVALID_ENTRY, "invalid port '%s'in '%s'" % (splits[1], entry)) else: if not check_port(item): raise FirewallError( errors.INVALID_ENTRY, "invalid port '%s' in '%s'" % (item, entry)) elif flag == "mark": if item.startswith("0x"): try: int_val = int(item, 16) except ValueError: raise FirewallError( errors.INVALID_ENTRY, "invalid mark '%s' in '%s'" % (item, entry)) else: try: int_val = int(item) except ValueError: raise FirewallError( errors.INVALID_ENTRY, "invalid mark '%s' in '%s'" % (item, entry)) if int_val < 0 or int_val > 4294967295: raise FirewallError( errors.INVALID_ENTRY, "invalid mark '%s' in '%s'" % (item, entry)) elif flag == "iface": if not checkInterface(item) or len(item) > 15: raise FirewallError( errors.INVALID_ENTRY, "invalid interface '%s' in '%s'" % (item, entry)) else: raise FirewallError(errors.INVALID_IPSET, "ipset type '%s' not usable" % ipset_type) def _check_config(self, config, item, all_config): if item == "type": if config not in IPSET_TYPES: raise FirewallError(errors.INVALID_TYPE, "'%s' is not valid ipset type" % config) if item == "options": for key in config.keys(): if key not in IPSET_CREATE_OPTIONS: raise FirewallError(errors.INVALID_IPSET, "ipset invalid option '%s'" % key) if key in [ "timeout", "hashsize", "maxelem" ]: try: int_value = int(config[key]) except ValueError: raise FirewallError( errors.INVALID_VALUE, "Option '%s': Value '%s' is not an integer" % \ (key, config[key])) if int_value < 0: raise FirewallError( errors.INVALID_VALUE, "Option '%s': Value '%s' is negative" % \ (key, config[key])) elif key == "family" and \ config[key] not in [ "inet", "inet6" ]: raise FirewallError(errors.INVALID_FAMILY, config[key]) def import_config(self, config): if "timeout" in config[4] and config[4]["timeout"] != "0": if len(config[5]) != 0: raise FirewallError(errors.IPSET_WITH_TIMEOUT) for entry in config[5]: IPSet.check_entry(entry, config[4], config[3]) super(IPSet, self).import_config(config) # PARSER class ipset_ContentHandler(IO_Object_ContentHandler): def startElement(self, name, attrs): IO_Object_ContentHandler.startElement(self, name, attrs) self.item.parser_check_element_attrs(name, attrs) if name == "ipset": if "type" in attrs: if attrs["type"] not in IPSET_TYPES: raise FirewallError(errors.INVALID_TYPE, "%s" % attrs["type"]) self.item.type = attrs["type"] if "version" in attrs: self.item.version = attrs["version"] elif name == "short": pass elif name == "description": pass elif name == "option": value = "" if "value" in attrs: value = attrs["value"] if attrs["name"] not in \ [ "family", "timeout", "hashsize", "maxelem" ]: raise FirewallError( errors.INVALID_OPTION, "Unknown option '%s'" % attrs["name"]) if self.item.type == "hash:mac" and attrs["name"] in [ "family" ]: raise FirewallError( errors.INVALID_OPTION, "Unsupported option '%s' for type '%s'" % \ (attrs["name"], self.item.type)) if attrs["name"] in [ "family", "timeout", "hashsize", "maxelem" ] \ and not value: raise FirewallError( errors.INVALID_OPTION, "Missing mandatory value of option '%s'" % attrs["name"]) if attrs["name"] in [ "timeout", "hashsize", "maxelem" ]: try: int_value = int(value) except ValueError: raise FirewallError( errors.INVALID_VALUE, "Option '%s': Value '%s' is not an integer" % \ (attrs["name"], value)) if int_value < 0: raise FirewallError( errors.INVALID_VALUE, "Option '%s': Value '%s' is negative" % \ (attrs["name"], value)) if attrs["name"] == "family" and value not in [ "inet", "inet6" ]: raise FirewallError(errors.INVALID_FAMILY, value) if attrs["name"] not in self.item.options: self.item.options[attrs["name"]] = value else: log.warning("Option %s already set, ignoring.", attrs["name"]) # nothing to do for entry and entries here def endElement(self, name): IO_Object_ContentHandler.endElement(self, name) if name == "entry": self.item.entries.append(self._element) def ipset_reader(filename, path): ipset = IPSet() if not filename.endswith(".xml"): raise FirewallError(errors.INVALID_NAME, "'%s' is missing .xml suffix" % filename) ipset.name = filename[:-4] ipset.check_name(ipset.name) ipset.filename = filename ipset.path = path ipset.builtin = False if path.startswith(config.ETC_FIREWALLD) else True ipset.default = ipset.builtin handler = ipset_ContentHandler(ipset) parser = sax.make_parser() parser.setContentHandler(handler) name = "%s/%s" % (path, filename) with open(name, "rb") as f: source = sax.InputSource(None) source.setByteStream(f) try: parser.parse(source) except sax.SAXParseException as msg: raise FirewallError(errors.INVALID_IPSET, "not a valid ipset file: %s" % \ msg.getException()) del handler del parser if "timeout" in ipset.options and ipset.options["timeout"] != "0" and \ len(ipset.entries) > 0: # no entries visible for ipsets with timeout log.warning("ipset '%s': timeout option is set, entries are ignored", ipset.name) del ipset.entries[:] i = 0 entries_set = set() while i < len(ipset.entries): if ipset.entries[i] in entries_set: log.warning("Entry %s already set, ignoring.", ipset.entries[i]) ipset.entries.pop(i) else: try: ipset.check_entry(ipset.entries[i], ipset.options, ipset.type) except FirewallError as e: log.warning("%s, ignoring.", e) ipset.entries.pop(i) else: entries_set.add(ipset.entries[i]) i += 1 del entries_set if PY2: ipset.encode_strings() return ipset def ipset_writer(ipset, path=None): _path = path if path else ipset.path if ipset.filename: name = "%s/%s" % (_path, ipset.filename) else: name = "%s/%s.xml" % (_path, ipset.name) if os.path.exists(name): try: shutil.copy2(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) dirpath = os.path.dirname(name) if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath): if not os.path.exists(config.ETC_FIREWALLD): os.mkdir(config.ETC_FIREWALLD, 0o750) os.mkdir(dirpath, 0o750) f = io.open(name, mode='wt', encoding='UTF-8') handler = IO_Object_XMLGenerator(f) handler.startDocument() # start ipset element attrs = { "type": ipset.type } if ipset.version and ipset.version != "": attrs["version"] = ipset.version handler.startElement("ipset", attrs) handler.ignorableWhitespace("\n") # short if ipset.short and ipset.short != "": handler.ignorableWhitespace(" ") handler.startElement("short", { }) handler.characters(ipset.short) handler.endElement("short") handler.ignorableWhitespace("\n") # description if ipset.description and ipset.description != "": handler.ignorableWhitespace(" ") handler.startElement("description", { }) handler.characters(ipset.description) handler.endElement("description") handler.ignorableWhitespace("\n") # options for key,value in ipset.options.items(): handler.ignorableWhitespace(" ") if value != "": handler.simpleElement("option", { "name": key, "value": value }) else: handler.simpleElement("option", { "name": key }) handler.ignorableWhitespace("\n") # entries for entry in ipset.entries: handler.ignorableWhitespace(" ") handler.startElement("entry", { }) handler.characters(entry) handler.endElement("entry") handler.ignorableWhitespace("\n") # end ipset element handler.endElement('ipset') handler.ignorableWhitespace("\n") handler.endDocument() f.close() del handler PKpge[Cc=== io/direct.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import xml.sax as sax import os import io import shutil from firewall import config from firewall.fw_types import LastUpdatedOrderedDict from firewall.functions import splitArgs, joinArgs, u2b_if_py2 from firewall.core.io.io_object import IO_Object, IO_Object_ContentHandler, \ IO_Object_XMLGenerator from firewall.core.logger import log from firewall.core import ipXtables from firewall.core import ebtables from firewall import errors from firewall.errors import FirewallError class direct_ContentHandler(IO_Object_ContentHandler): def __init__(self, item): IO_Object_ContentHandler.__init__(self, item) self.direct = False def startElement(self, name, attrs): IO_Object_ContentHandler.startElement(self, name, attrs) self.item.parser_check_element_attrs(name, attrs) if name == "direct": if self.direct: raise FirewallError(errors.PARSE_ERROR, "More than one direct tag.") self.direct = True elif name == "chain": if not self.direct: log.error("Parse Error: chain outside of direct") return ipv = attrs["ipv"] table = attrs["table"] chain = attrs["chain"] self.item.add_chain(u2b_if_py2(ipv), u2b_if_py2(table), u2b_if_py2(chain)) elif name == "rule": if not self.direct: log.error("Parse Error: rule outside of direct") return ipv = attrs["ipv"] if ipv not in [ "ipv4", "ipv6", "eb" ]: raise FirewallError(errors.INVALID_IPV, "'%s' not from {'ipv4'|'ipv6'|'eb'}" % ipv) table = attrs["table"] chain = attrs["chain"] try: priority = int(attrs["priority"]) except ValueError: log.error("Parse Error: %s is not a valid priority" % attrs["priority"]) return self._rule = [ u2b_if_py2(ipv), u2b_if_py2(table), u2b_if_py2(chain), priority ] elif name == "passthrough": if not self.direct: log.error("Parse Error: command outside of direct") return ipv = attrs["ipv"] self._passthrough = [ u2b_if_py2(ipv) ] else: log.error('Unknown XML element %s' % name) return def endElement(self, name): IO_Object_ContentHandler.endElement(self, name) if name == "rule": if self._element: # add arguments self._rule.append([ u2b_if_py2(x) for x in splitArgs(self._element) ]) self.item.add_rule(*self._rule) else: log.error("Error: rule does not have any arguments, ignoring.") self._rule = None elif name == "passthrough": if self._element: # add arguments self._passthrough.append([ u2b_if_py2(x) for x in splitArgs(self._element) ]) self.item.add_passthrough(*self._passthrough) else: log.error("Error: passthrough does not have any arguments, " + "ignoring.") self._passthrough = None class Direct(IO_Object): """ Direct class """ IMPORT_EXPORT_STRUCTURE = ( # chain: [ ipv, table, [ chain ] ] ( "chains", [ ( "", "", "" ), ], ), # a(sss) # rule: [ ipv, table, chain, [ priority, [ arg ] ] ] ( "rules", [ ( "", "", "", 0, [ "" ] ), ], ), # a(sssias) # passthrough: [ ipv, [ [ arg ] ] ] ( "passthroughs", [ ( "", [ "" ]), ], ), # a(sas) ) DBUS_SIGNATURE = '(a(sss)a(sssias)a(sas))' PARSER_REQUIRED_ELEMENT_ATTRS = { "direct": None, "chain": [ "ipv", "table", "chain" ], "rule": [ "ipv", "table", "chain", "priority" ], "passthrough": [ "ipv" ] } PARSER_OPTIONAL_ELEMENT_ATTRS = { } def __init__(self, filename): super(Direct, self).__init__() self.filename = filename self.chains = LastUpdatedOrderedDict() self.rules = LastUpdatedOrderedDict() self.passthroughs = LastUpdatedOrderedDict() def _check_config(self, conf, item, all_conf): pass # check arg lists def export_config(self): ret = [ ] x = [ ] for key in self.chains: for chain in self.chains[key]: x.append(tuple(list(key) + list([chain]))) ret.append(x) x = [ ] for key in self.rules: for rule in self.rules[key]: x.append(tuple((key[0], key[1], key[2], rule[0], list(rule[1])))) ret.append(x) x = [ ] for key in self.passthroughs: for rule in self.passthroughs[key]: x.append(tuple((key, list(rule)))) ret.append(x) return tuple(ret) def import_config(self, conf): self.cleanup() self.check_config(conf) for i,(element,dummy) in enumerate(self.IMPORT_EXPORT_STRUCTURE): if element == "chains": for x in conf[i]: self.add_chain(*x) if element == "rules": for x in conf[i]: self.add_rule(*x) if element == "passthroughs": for x in conf[i]: self.add_passthrough(*x) def cleanup(self): self.chains.clear() self.rules.clear() self.passthroughs.clear() def output(self): print("chains") for key in self.chains: print(" (%s, %s): %s" % (key[0], key[1], ",".join(self.chains[key]))) print("rules") for key in self.rules: print(" (%s, %s, %s):" % (key[0], key[1], key[2])) for (priority,args) in self.rules[key]: print(" (%d, ('%s'))" % (priority, "','".join(args))) print("passthroughs") for key in self.passthroughs: print(" %s:" % (key)) for args in self.passthroughs[key]: print(" ('%s')" % ("','".join(args))) def _check_ipv(self, ipv): ipvs = ['ipv4', 'ipv6', 'eb'] if ipv not in ipvs: raise FirewallError(errors.INVALID_IPV, "'%s' not in '%s'" % (ipv, ipvs)) def _check_ipv_table(self, ipv, table): self._check_ipv(ipv) tables = ipXtables.BUILT_IN_CHAINS.keys() if ipv in ['ipv4', 'ipv6'] \ else ebtables.BUILT_IN_CHAINS.keys() if table not in tables: raise FirewallError(errors.INVALID_TABLE, "'%s' not in '%s'" % (table, tables)) # chains def add_chain(self, ipv, table, chain): self._check_ipv_table(ipv, table) key = (ipv, table) if key not in self.chains: self.chains[key] = [ ] if chain not in self.chains[key]: self.chains[key].append(chain) else: log.warning("Chain '%s' for table '%s' with ipv '%s' " % \ (chain, table, ipv) + "already in list, ignoring") def remove_chain(self, ipv, table, chain): self._check_ipv_table(ipv, table) key = (ipv, table) if key in self.chains and chain in self.chains[key]: self.chains[key].remove(chain) if len(self.chains[key]) == 0: del self.chains[key] else: raise ValueError( \ "Chain '%s' with table '%s' with ipv '%s' not in list" % \ (chain, table, ipv)) def query_chain(self, ipv, table, chain): self._check_ipv_table(ipv, table) key = (ipv, table) return (key in self.chains and chain in self.chains[key]) def get_chains(self, ipv, table): self._check_ipv_table(ipv, table) key = (ipv, table) if key in self.chains: return self.chains[key] else: raise ValueError("No chains for table '%s' with ipv '%s'" % \ (table, ipv)) def get_all_chains(self): return self.chains # rules def add_rule(self, ipv, table, chain, priority, args): self._check_ipv_table(ipv, table) key = (ipv, table, chain) if key not in self.rules: self.rules[key] = LastUpdatedOrderedDict() value = (priority, tuple(args)) if value not in self.rules[key]: self.rules[key][value] = priority else: log.warning("Rule '%s' for table '%s' and chain '%s' " % \ ("',".join(args), table, chain) + "with ipv '%s' and priority %d " % (ipv, priority) + "already in list, ignoring") def remove_rule(self, ipv, table, chain, priority, args): self._check_ipv_table(ipv, table) key = (ipv, table, chain) value = (priority, tuple(args)) if key in self.rules and value in self.rules[key]: del self.rules[key][value] if len(self.rules[key]) == 0: del self.rules[key] else: raise ValueError("Rule '%s' for table '%s' and chain '%s' " % \ ("',".join(args), table, chain) + \ "with ipv '%s' and priority %d not in list" % (ipv, priority)) def remove_rules(self, ipv, table, chain): self._check_ipv_table(ipv, table) key = (ipv, table, chain) if key in self.rules: for value in self.rules[key].keys(): del self.rules[key][value] if len(self.rules[key]) == 0: del self.rules[key] def query_rule(self, ipv, table, chain, priority, args): self._check_ipv_table(ipv, table) key = (ipv, table, chain) value = (priority, tuple(args)) return (key in self.rules and value in self.rules[key]) def get_rules(self, ipv, table, chain): self._check_ipv_table(ipv, table) key = (ipv, table, chain) if key in self.rules: return self.rules[key] else: raise ValueError("No rules for table '%s' and chain '%s' " %\ (table, chain) + "with ipv '%s'" % (ipv)) def get_all_rules(self): return self.rules # # passthrough # def add_passthrough(self, ipv, args): self._check_ipv(ipv) if ipv not in self.passthroughs: self.passthroughs[ipv] = [ ] if args not in self.passthroughs[ipv]: self.passthroughs[ipv].append(args) else: log.warning("Passthrough '%s' for ipv '%s'" % \ ("',".join(args), ipv) + "already in list, ignoring") def remove_passthrough(self, ipv, args): self._check_ipv(ipv) if ipv in self.passthroughs and args in self.passthroughs[ipv]: self.passthroughs[ipv].remove(args) if len(self.passthroughs[ipv]) == 0: del self.passthroughs[ipv] else: raise ValueError("Passthrough '%s' for ipv '%s'" % \ ("',".join(args), ipv) + "not in list") def query_passthrough(self, ipv, args): self._check_ipv(ipv) return ipv in self.passthroughs and args in self.passthroughs[ipv] def get_passthroughs(self, ipv): self._check_ipv(ipv) if ipv in self.passthroughs: return self.passthroughs[ipv] else: raise ValueError("No passthroughs for ipv '%s'" % (ipv)) def get_all_passthroughs(self): return self.passthroughs # read def read(self): self.cleanup() if not self.filename.endswith(".xml"): raise FirewallError(errors.INVALID_NAME, "'%s' is missing .xml suffix" % self.filename) handler = direct_ContentHandler(self) parser = sax.make_parser() parser.setContentHandler(handler) with open(self.filename, "rb") as f: source = sax.InputSource(None) source.setByteStream(f) try: parser.parse(source) except sax.SAXParseException as msg: raise FirewallError(errors.INVALID_TYPE, "Not a valid file: %s" % \ msg.getException()) def write(self): if os.path.exists(self.filename): try: shutil.copy2(self.filename, "%s.old" % self.filename) except Exception as msg: raise IOError("Backup of '%s' failed: %s" % (self.filename, msg)) if not os.path.exists(config.ETC_FIREWALLD): os.mkdir(config.ETC_FIREWALLD, 0o750) f = io.open(self.filename, mode='wt', encoding='UTF-8') handler = IO_Object_XMLGenerator(f) handler.startDocument() # start whitelist element handler.startElement("direct", { }) handler.ignorableWhitespace("\n") # chains for key in self.chains: (ipv, table) = key for chain in self.chains[key]: handler.ignorableWhitespace(" ") handler.simpleElement("chain", { "ipv": ipv, "table": table, "chain": chain }) handler.ignorableWhitespace("\n") # rules for key in self.rules: (ipv, table, chain) = key for (priority, args) in self.rules[key]: if len(args) < 1: continue handler.ignorableWhitespace(" ") handler.startElement("rule", { "ipv": ipv, "table": table, "chain": chain, "priority": "%d" % priority }) handler.ignorableWhitespace(sax.saxutils.escape(joinArgs(args))) handler.endElement("rule") handler.ignorableWhitespace("\n") # passthroughs for ipv in self.passthroughs: for args in self.passthroughs[ipv]: if len(args) < 1: continue handler.ignorableWhitespace(" ") handler.startElement("passthrough", { "ipv": ipv }) handler.ignorableWhitespace(sax.saxutils.escape(joinArgs(args))) handler.endElement("passthrough") handler.ignorableWhitespace("\n") # end zone element handler.endElement("direct") handler.ignorableWhitespace("\n") handler.endDocument() f.close() del handler PKpge[m io/ifcfg.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """ifcfg file parser""" __all__ = [ "ifcfg" ] import os.path import io import tempfile import shutil from firewall.core.logger import log from firewall.functions import b2u, u2b, PY2 class ifcfg(object): def __init__(self, filename): self._config = { } self._deleted = [ ] self.filename = filename self.clear() def clear(self): self._config = { } self._deleted = [ ] def cleanup(self): self._config.clear() def get(self, key): return self._config.get(key.strip()) def set(self, key, value): _key = b2u(key.strip()) self._config[_key] = b2u(value.strip()) if _key in self._deleted: self._deleted.remove(_key) def __str__(self): s = "" for (key, value) in self._config.items(): if s: s += '\n' s += '%s=%s' % (key, value) return u2b(s) if PY2 else s # load self.filename def read(self): self.clear() try: f = open(self.filename, "r") except Exception as msg: log.error("Failed to load '%s': %s", self.filename, msg) raise for line in f: if not line: break line = line.strip() if len(line) < 1 or line[0] in ['#', ';']: continue # get key/value pair pair = [ x.strip() for x in line.split("=", 1) ] if len(pair) != 2: continue if len(pair[1]) >= 2 and \ pair[1].startswith('"') and pair[1].endswith('"'): pair[1] = pair[1][1:-1] if pair[1] == '': continue elif self._config.get(pair[0]) is not None: log.warning("%s: Duplicate option definition: '%s'", self.filename, line.strip()) continue self._config[pair[0]] = pair[1] f.close() def write(self): if len(self._config) < 1: # no changes: nothing to do return # handled keys done = [ ] try: temp_file = tempfile.NamedTemporaryFile( mode='wt', prefix="%s." % os.path.basename(self.filename), dir=os.path.dirname(self.filename), delete=False) except Exception as msg: log.error("Failed to open temporary file: %s" % msg) raise modified = False empty = False try: f = io.open(self.filename, mode='rt', encoding='UTF-8') except Exception as msg: if os.path.exists(self.filename): log.error("Failed to open '%s': %s" % (self.filename, msg)) raise else: f = None else: for line in f: if not line: break # remove newline line = line.strip("\n") if len(line) < 1: if not empty: temp_file.write(u"\n") empty = True elif line[0] == '#': empty = False temp_file.write(line) temp_file.write(u"\n") else: p = line.split("=", 1) if len(p) != 2: empty = False temp_file.write(line+u"\n") continue key = p[0].strip() value = p[1].strip() if len(value) >= 2 and \ value.startswith('"') and value.endswith('"'): value = value[1:-1] # check for modified key/value pairs if key not in done: if key in self._config and self._config[key] != value: empty = False temp_file.write(u'%s=%s\n' % (key, self._config[key])) modified = True elif key in self._deleted: modified = True else: empty = False temp_file.write(line+u"\n") done.append(key) else: modified = True # write remaining key/value pairs if len(self._config) > 0: for (key, value) in self._config.items(): if key in done: continue if not empty: empty = True temp_file.write(u'%s=%s\n' % (key, value)) modified = True if f: f.close() temp_file.close() if not modified: # not modified: remove tempfile os.remove(temp_file.name) return # make backup if os.path.exists(self.filename): try: shutil.copy2(self.filename, "%s.bak" % self.filename) except Exception as msg: os.remove(temp_file.name) raise IOError("Backup of '%s' failed: %s" % (self.filename, msg)) # copy tempfile try: shutil.move(temp_file.name, self.filename) except Exception as msg: os.remove(temp_file.name) raise IOError("Failed to create '%s': %s" % (self.filename, msg)) else: os.chmod(self.filename, 0o600) PKpge[5io/icmptype.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "IcmpType", "icmptype_reader", "icmptype_writer" ] import xml.sax as sax import os import io import shutil from firewall import config from firewall.functions import u2b_if_py2 from firewall.core.io.io_object import PY2, IO_Object, \ IO_Object_ContentHandler, IO_Object_XMLGenerator from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError class IcmpType(IO_Object): IMPORT_EXPORT_STRUCTURE = ( ( "version", "" ), # s ( "short", "" ), # s ( "description", "" ), # s ( "destination", [ "", ], ), # as ) DBUS_SIGNATURE = '(sssas)' ADDITIONAL_ALNUM_CHARS = [ "_", "-" ] PARSER_REQUIRED_ELEMENT_ATTRS = { "short": None, "description": None, "icmptype": None, } PARSER_OPTIONAL_ELEMENT_ATTRS = { "icmptype": [ "name", "version" ], "destination": [ "ipv4", "ipv6" ], } def __init__(self): super(IcmpType, self).__init__() self.version = "" self.short = "" self.description = "" self.destination = [ ] def cleanup(self): self.version = "" self.short = "" self.description = "" del self.destination[:] def encode_strings(self): """ HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.""" self.version = u2b_if_py2(self.version) self.short = u2b_if_py2(self.short) self.description = u2b_if_py2(self.description) self.destination = [u2b_if_py2(m) for m in self.destination] def _check_config(self, config, item, all_config): if item == "destination": for destination in config: if destination not in [ "ipv4", "ipv6" ]: raise FirewallError(errors.INVALID_DESTINATION, "'%s' not from {'ipv4'|'ipv6'}" % \ destination) # PARSER class icmptype_ContentHandler(IO_Object_ContentHandler): def startElement(self, name, attrs): IO_Object_ContentHandler.startElement(self, name, attrs) self.item.parser_check_element_attrs(name, attrs) if name == "icmptype": if "name" in attrs: log.warning("Ignoring deprecated attribute name='%s'" % attrs["name"]) if "version" in attrs: self.item.version = attrs["version"] elif name == "short": pass elif name == "description": pass elif name == "destination": for x in [ "ipv4", "ipv6" ]: if x in attrs and \ attrs[x].lower() in [ "yes", "true" ]: self.item.destination.append(str(x)) def icmptype_reader(filename, path): icmptype = IcmpType() if not filename.endswith(".xml"): raise FirewallError(errors.INVALID_NAME, "%s is missing .xml suffix" % filename) icmptype.name = filename[:-4] icmptype.check_name(icmptype.name) icmptype.filename = filename icmptype.path = path icmptype.builtin = False if path.startswith(config.ETC_FIREWALLD) else True icmptype.default = icmptype.builtin handler = icmptype_ContentHandler(icmptype) parser = sax.make_parser() parser.setContentHandler(handler) name = "%s/%s" % (path, filename) with open(name, "rb") as f: source = sax.InputSource(None) source.setByteStream(f) try: parser.parse(source) except sax.SAXParseException as msg: raise FirewallError(errors.INVALID_ICMPTYPE, "not a valid icmptype file: %s" % \ msg.getException()) del handler del parser if PY2: icmptype.encode_strings() return icmptype def icmptype_writer(icmptype, path=None): _path = path if path else icmptype.path if icmptype.filename: name = "%s/%s" % (_path, icmptype.filename) else: name = "%s/%s.xml" % (_path, icmptype.name) if os.path.exists(name): try: shutil.copy2(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) dirpath = os.path.dirname(name) if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath): if not os.path.exists(config.ETC_FIREWALLD): os.mkdir(config.ETC_FIREWALLD, 0o750) os.mkdir(dirpath, 0o750) f = io.open(name, mode='wt', encoding='UTF-8') handler = IO_Object_XMLGenerator(f) handler.startDocument() # start icmptype element attrs = {} if icmptype.version and icmptype.version != "": attrs["version"] = icmptype.version handler.startElement("icmptype", attrs) handler.ignorableWhitespace("\n") # short if icmptype.short and icmptype.short != "": handler.ignorableWhitespace(" ") handler.startElement("short", { }) handler.characters(icmptype.short) handler.endElement("short") handler.ignorableWhitespace("\n") # description if icmptype.description and icmptype.description != "": handler.ignorableWhitespace(" ") handler.startElement("description", { }) handler.characters(icmptype.description) handler.endElement("description") handler.ignorableWhitespace("\n") # destination if icmptype.destination: handler.ignorableWhitespace(" ") attrs = { } for x in icmptype.destination: attrs[x] = "yes" handler.simpleElement("destination", attrs) handler.ignorableWhitespace("\n") # end icmptype element handler.endElement('icmptype') handler.ignorableWhitespace("\n") handler.endDocument() f.close() del handler PKpge[8MM io/zone.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "Zone", "zone_reader", "zone_writer" ] import xml.sax as sax import os import io import shutil from firewall import config from firewall.functions import checkIPnMask, checkIP6nMask, checkInterface, uniqify, max_zone_name_len, u2b_if_py2, check_mac from firewall.core.base import DEFAULT_ZONE_TARGET, ZONE_TARGETS from firewall.core.io.io_object import PY2, IO_Object, \ IO_Object_ContentHandler, IO_Object_XMLGenerator from firewall.core.io.policy import common_startElement, common_endElement, common_check_config, common_writer from firewall.core import rich from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError class Zone(IO_Object): """ Zone class """ IMPORT_EXPORT_STRUCTURE = ( ( "version", "" ), # s ( "short", "" ), # s ( "description", "" ), # s ( "UNUSED", False ), # b ( "target", "" ), # s ( "services", [ "", ], ), # as ( "ports", [ ( "", "" ), ], ), # a(ss) ( "icmp_blocks", [ "", ], ), # as ( "masquerade", False ), # b ( "forward_ports", [ ( "", "", "", "" ), ], ), # a(ssss) ( "interfaces", [ "" ] ), # as ( "sources", [ "" ] ), # as ( "rules_str", [ "" ] ), # as ( "protocols", [ "", ], ), # as ( "source_ports", [ ( "", "" ), ], ), # a(ss) ( "icmp_block_inversion", False ), # b ( "forward", False ), # b ) ADDITIONAL_ALNUM_CHARS = [ "_", "-", "/" ] PARSER_REQUIRED_ELEMENT_ATTRS = { "short": None, "description": None, "zone": None, "service": [ "name" ], "port": [ "port", "protocol" ], "icmp-block": [ "name" ], "icmp-type": [ "name" ], "forward": None, "forward-port": [ "port", "protocol" ], "interface": [ "name" ], "rule": None, "source": None, "destination": None, "protocol": [ "value" ], "source-port": [ "port", "protocol" ], "log": None, "audit": None, "accept": None, "reject": None, "drop": None, "mark": [ "set" ], "limit": [ "value" ], "icmp-block-inversion": None, } PARSER_OPTIONAL_ELEMENT_ATTRS = { "zone": [ "name", "immutable", "target", "version" ], "masquerade": [ "enabled" ], "forward-port": [ "to-port", "to-addr" ], "rule": [ "family", "priority" ], "source": [ "address", "mac", "invert", "family", "ipset" ], "destination": [ "address", "invert", "ipset" ], "log": [ "prefix", "level" ], "reject": [ "type" ], "limit": ["burst"], } @staticmethod def index_of(element): for i, (el, dummy) in enumerate(Zone.IMPORT_EXPORT_STRUCTURE): if el == element: return i raise FirewallError(errors.UNKNOWN_ERROR, "index_of()") def __init__(self): super(Zone, self).__init__() self.version = "" self.short = "" self.description = "" self.UNUSED = False self.target = DEFAULT_ZONE_TARGET self.services = [ ] self.ports = [ ] self.protocols = [ ] self.icmp_blocks = [ ] self.forward = False self.masquerade = False self.forward_ports = [ ] self.source_ports = [ ] self.interfaces = [ ] self.sources = [ ] self.fw_config = None # to be able to check services and a icmp_blocks self.rules = [ ] self.rules_str = [ ] self.icmp_block_inversion = False self.combined = False self.applied = False def cleanup(self): self.version = "" self.short = "" self.description = "" self.UNUSED = False self.target = DEFAULT_ZONE_TARGET del self.services[:] del self.ports[:] del self.protocols[:] del self.icmp_blocks[:] self.forward = False self.masquerade = False del self.forward_ports[:] del self.source_ports[:] del self.interfaces[:] del self.sources[:] self.fw_config = None # to be able to check services and a icmp_blocks del self.rules[:] del self.rules_str[:] self.icmp_block_inversion = False self.combined = False self.applied = False def encode_strings(self): """ HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.""" self.version = u2b_if_py2(self.version) self.short = u2b_if_py2(self.short) self.description = u2b_if_py2(self.description) self.target = u2b_if_py2(self.target) self.services = [u2b_if_py2(s) for s in self.services] self.ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr) in self.ports] self.protocols = [u2b_if_py2(pr) for pr in self.protocols] self.icmp_blocks = [u2b_if_py2(i) for i in self.icmp_blocks] self.forward_ports = [(u2b_if_py2(p1),u2b_if_py2(p2),u2b_if_py2(p3),u2b_if_py2(p4)) for (p1,p2,p3,p4) in self.forward_ports] self.source_ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr) in self.source_ports] self.interfaces = [u2b_if_py2(i) for i in self.interfaces] self.sources = [u2b_if_py2(s) for s in self.sources] self.rules = [u2b_if_py2(s) for s in self.rules] self.rules_str = [u2b_if_py2(s) for s in self.rules_str] def __setattr__(self, name, value): if name == "rules_str": self.rules = [rich.Rich_Rule(rule_str=s) for s in value] # must convert back to string to get the canonical string. super(Zone, self).__setattr__(name, [str(s) for s in self.rules]) else: super(Zone, self).__setattr__(name, value) def export_config_dict(self): conf = super(Zone, self).export_config_dict() del conf["UNUSED"] return conf def _check_config(self, config, item, all_config): common_check_config(self, config, item, all_config) if item == "target": if config not in ZONE_TARGETS: raise FirewallError(errors.INVALID_TARGET, config) elif item == "interfaces": for interface in config: if not checkInterface(interface): raise FirewallError(errors.INVALID_INTERFACE, interface) if self.fw_config: for zone in self.fw_config.get_zones(): if zone == self.name: continue if interface in self.fw_config.get_zone(zone).interfaces: raise FirewallError(errors.INVALID_INTERFACE, "interface '{}' already bound to zone '{}'".format(interface, zone)) elif item == "sources": for source in config: if not checkIPnMask(source) and not checkIP6nMask(source) and \ not check_mac(source) and not source.startswith("ipset:"): raise FirewallError(errors.INVALID_ADDR, source) if self.fw_config: for zone in self.fw_config.get_zones(): if zone == self.name: continue if source in self.fw_config.get_zone(zone).sources: raise FirewallError(errors.INVALID_ADDR, "source '{}' already bound to zone '{}'".format(source, zone)) def check_name(self, name): super(Zone, self).check_name(name) if name.startswith('/'): raise FirewallError(errors.INVALID_NAME, "'%s' can't start with '/'" % name) elif name.endswith('/'): raise FirewallError(errors.INVALID_NAME, "'%s' can't end with '/'" % name) elif name.count('/') > 1: raise FirewallError(errors.INVALID_NAME, "more than one '/' in '%s'" % name) else: if "/" in name: checked_name = name[:name.find('/')] else: checked_name = name if len(checked_name) > max_zone_name_len(): raise FirewallError(errors.INVALID_NAME, "Zone of '%s' has %d chars, max is %d %s" % ( name, len(checked_name), max_zone_name_len(), self.combined)) if self.fw_config: if checked_name in self.fw_config.get_policy_objects(): raise FirewallError(errors.NAME_CONFLICT, "Zones can't have the same name as a policy.") def combine(self, zone): self.combined = True self.filename = None self.version = "" self.short = "" self.description = "" for interface in zone.interfaces: if interface not in self.interfaces: self.interfaces.append(interface) for source in zone.sources: if source not in self.sources: self.sources.append(source) for service in zone.services: if service not in self.services: self.services.append(service) for port in zone.ports: if port not in self.ports: self.ports.append(port) for proto in zone.protocols: if proto not in self.protocols: self.protocols.append(proto) for icmp in zone.icmp_blocks: if icmp not in self.icmp_blocks: self.icmp_blocks.append(icmp) if zone.forward: self.forward = True if zone.masquerade: self.masquerade = True for forward in zone.forward_ports: if forward not in self.forward_ports: self.forward_ports.append(forward) for port in zone.source_ports: if port not in self.source_ports: self.source_ports.append(port) for rule in zone.rules: self.rules.append(rule) self.rules_str.append(str(rule)) if zone.icmp_block_inversion: self.icmp_block_inversion = True # PARSER class zone_ContentHandler(IO_Object_ContentHandler): def __init__(self, item): IO_Object_ContentHandler.__init__(self, item) self._rule = None self._rule_error = False self._limit_ok = None def startElement(self, name, attrs): IO_Object_ContentHandler.startElement(self, name, attrs) if self._rule_error: return self.item.parser_check_element_attrs(name, attrs) if common_startElement(self, name, attrs): return elif name == "zone": if "name" in attrs: log.warning("Ignoring deprecated attribute name='%s'", attrs["name"]) if "version" in attrs: self.item.version = attrs["version"] if "immutable" in attrs: log.warning("Ignoring deprecated attribute immutable='%s'", attrs["immutable"]) if "target" in attrs: target = attrs["target"] if target not in ZONE_TARGETS: raise FirewallError(errors.INVALID_TARGET, target) if target != "" and target != DEFAULT_ZONE_TARGET: self.item.target = target elif name == "forward": if self.item.forward: log.warning("Forward already set, ignoring.") else: self.item.forward = True elif name == "interface": if self._rule: log.warning('Invalid rule: interface use in rule.') self._rule_error = True return # zone bound to interface if "name" not in attrs: log.warning('Invalid interface: Name missing.') self._rule_error = True return if attrs["name"] not in self.item.interfaces: self.item.interfaces.append(attrs["name"]) else: log.warning("Interface '%s' already set, ignoring.", attrs["name"]) elif name == "source": if self._rule: if self._rule.source: log.warning("Invalid rule: More than one source in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return invert = False if "invert" in attrs and \ attrs["invert"].lower() in [ "yes", "true" ]: invert = True addr = mac = ipset = None if "address" in attrs: addr = attrs["address"] if "mac" in attrs: mac = attrs["mac"] if "ipset" in attrs: ipset = attrs["ipset"] self._rule.source = rich.Rich_Source(addr, mac, ipset, invert=invert) return # zone bound to source if "address" not in attrs and "ipset" not in attrs: log.warning('Invalid source: No address no ipset.') return if "address" in attrs and "ipset" in attrs: log.warning('Invalid source: Address and ipset.') return if "family" in attrs: log.warning("Ignoring deprecated attribute family='%s'", attrs["family"]) if "invert" in attrs: log.warning('Invalid source: Invertion not allowed here.') return if "address" in attrs: if not checkIPnMask(attrs["address"]) and \ not checkIP6nMask(attrs["address"]) and \ not check_mac(attrs["address"]): raise FirewallError(errors.INVALID_ADDR, attrs["address"]) if "ipset" in attrs: entry = "ipset:%s" % attrs["ipset"] if entry not in self.item.sources: self.item.sources.append(entry) else: log.warning("Source '%s' already set, ignoring.", attrs["address"]) if "address" in attrs: entry = attrs["address"] if entry not in self.item.sources: self.item.sources.append(entry) else: log.warning("Source '%s' already set, ignoring.", attrs["address"]) elif name == "icmp-block-inversion": if self.item.icmp_block_inversion: log.warning("Icmp-Block-Inversion already set, ignoring.") else: self.item.icmp_block_inversion = True else: log.warning("Unknown XML element '%s'", name) return def endElement(self, name): IO_Object_ContentHandler.endElement(self, name) common_endElement(self, name) def zone_reader(filename, path, no_check_name=False): zone = Zone() if not filename.endswith(".xml"): raise FirewallError(errors.INVALID_NAME, "'%s' is missing .xml suffix" % filename) zone.name = filename[:-4] if not no_check_name: zone.check_name(zone.name) zone.filename = filename zone.path = path zone.builtin = False if path.startswith(config.ETC_FIREWALLD) else True zone.default = zone.builtin handler = zone_ContentHandler(zone) parser = sax.make_parser() parser.setContentHandler(handler) name = "%s/%s" % (path, filename) with open(name, "rb") as f: source = sax.InputSource(None) source.setByteStream(f) try: parser.parse(source) except sax.SAXParseException as msg: raise FirewallError(errors.INVALID_ZONE, "not a valid zone file: %s" % \ msg.getException()) del handler del parser if PY2: zone.encode_strings() return zone def zone_writer(zone, path=None): _path = path if path else zone.path if zone.filename: name = "%s/%s" % (_path, zone.filename) else: name = "%s/%s.xml" % (_path, zone.name) if os.path.exists(name): try: shutil.copy2(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) dirpath = os.path.dirname(name) if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath): if not os.path.exists(config.ETC_FIREWALLD): os.mkdir(config.ETC_FIREWALLD, 0o750) os.mkdir(dirpath, 0o750) f = io.open(name, mode='wt', encoding='UTF-8') handler = IO_Object_XMLGenerator(f) handler.startDocument() # start zone element attrs = {} if zone.version and zone.version != "": attrs["version"] = zone.version if zone.target != DEFAULT_ZONE_TARGET: attrs["target"] = zone.target handler.startElement("zone", attrs) handler.ignorableWhitespace("\n") common_writer(zone, handler) # interfaces for interface in uniqify(zone.interfaces): handler.ignorableWhitespace(" ") handler.simpleElement("interface", { "name": interface }) handler.ignorableWhitespace("\n") # source for source in uniqify(zone.sources): handler.ignorableWhitespace(" ") if "ipset:" in source: handler.simpleElement("source", { "ipset": source[6:] }) else: handler.simpleElement("source", { "address": source }) handler.ignorableWhitespace("\n") # icmp-block-inversion if zone.icmp_block_inversion: handler.ignorableWhitespace(" ") handler.simpleElement("icmp-block-inversion", { }) handler.ignorableWhitespace("\n") # forward if zone.forward: handler.ignorableWhitespace(" ") handler.simpleElement("forward", { }) handler.ignorableWhitespace("\n") # end zone element handler.endElement("zone") handler.ignorableWhitespace("\n") handler.endDocument() f.close() del handler PKpge[mL22 io/service.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "Service", "service_reader", "service_writer" ] import xml.sax as sax import os import io import shutil from firewall import config from firewall.functions import u2b_if_py2 from firewall.core.io.io_object import PY2, IO_Object, \ IO_Object_ContentHandler, IO_Object_XMLGenerator, check_port, \ check_tcpudp, check_protocol, check_address from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError class Service(IO_Object): IMPORT_EXPORT_STRUCTURE = ( ( "version", "" ), ( "short", "" ), ( "description", "" ), ( "ports", [ ( "", "" ), ], ), ( "modules", [ "", ], ), ( "destination", { "": "", }, ), ( "protocols", [ "", ], ), ( "source_ports", [ ( "", "" ), ], ), ( "includes", [ "" ], ), ( "helpers", [ "", ], ), ) ADDITIONAL_ALNUM_CHARS = [ "_", "-" ] PARSER_REQUIRED_ELEMENT_ATTRS = { "short": None, "description": None, "service": None, } PARSER_OPTIONAL_ELEMENT_ATTRS = { "service": [ "name", "version" ], "port": [ "port", "protocol" ], "protocol": [ "value" ], "module": [ "name" ], "destination": [ "ipv4", "ipv6" ], "source-port": [ "port", "protocol" ], "include": [ "service" ], "helper": [ "name" ], } def __init__(self): super(Service, self).__init__() self.version = "" self.short = "" self.description = "" self.ports = [ ] self.protocols = [ ] self.modules = [ ] self.destination = { } self.source_ports = [ ] self.includes = [ ] self.helpers = [ ] def cleanup(self): self.version = "" self.short = "" self.description = "" del self.ports[:] del self.protocols[:] del self.modules[:] self.destination.clear() del self.source_ports[:] del self.includes[:] del self.helpers[:] def encode_strings(self): """ HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.""" self.version = u2b_if_py2(self.version) self.short = u2b_if_py2(self.short) self.description = u2b_if_py2(self.description) self.ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr) in self.ports] self.modules = [u2b_if_py2(m) for m in self.modules] self.destination = {u2b_if_py2(k):u2b_if_py2(v) for k,v in self.destination.items()} self.protocols = [u2b_if_py2(pr) for pr in self.protocols] self.source_ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr) in self.source_ports] self.includes = [u2b_if_py2(s) for s in self.includes] self.helpers = [u2b_if_py2(s) for s in self.helpers] def _check_config(self, config, item, all_config): if item == "ports": for port in config: if port[0] != "": check_port(port[0]) check_tcpudp(port[1]) else: # only protocol check_protocol(port[1]) elif item == "protocols": for proto in config: check_protocol(proto) elif item == "source_ports": for port in config: check_port(port[0]) check_tcpudp(port[1]) elif item == "destination": for destination in config: if destination not in [ "ipv4", "ipv6" ]: raise FirewallError(errors.INVALID_DESTINATION, "'%s' not in {'ipv4'|'ipv6'}" % \ destination) check_address(destination, config[destination]) elif item == "modules": for module in config: if module.startswith("nf_conntrack_"): module = module.replace("nf_conntrack_", "") if "_" in module: module = module.replace("_", "-") if len(module) < 2: raise FirewallError(errors.INVALID_MODULE, module) # PARSER class service_ContentHandler(IO_Object_ContentHandler): def startElement(self, name, attrs): IO_Object_ContentHandler.startElement(self, name, attrs) self.item.parser_check_element_attrs(name, attrs) if name == "service": if "name" in attrs: log.warning("Ignoring deprecated attribute name='%s'", attrs["name"]) if "version" in attrs: self.item.version = attrs["version"] elif name == "short": pass elif name == "description": pass elif name == "port": if attrs["port"] != "": check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) entry = (attrs["port"], attrs["protocol"]) if entry not in self.item.ports: self.item.ports.append(entry) else: log.warning("Port '%s/%s' already set, ignoring.", attrs["port"], attrs["protocol"]) else: check_protocol(attrs["protocol"]) if attrs["protocol"] not in self.item.protocols: self.item.protocols.append(attrs["protocol"]) else: log.warning("Protocol '%s' already set, ignoring.", attrs["protocol"]) elif name == "protocol": check_protocol(attrs["value"]) if attrs["value"] not in self.item.protocols: self.item.protocols.append(attrs["value"]) else: log.warning("Protocol '%s' already set, ignoring.", attrs["value"]) elif name == "source-port": check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) entry = (attrs["port"], attrs["protocol"]) if entry not in self.item.source_ports: self.item.source_ports.append(entry) else: log.warning("SourcePort '%s/%s' already set, ignoring.", attrs["port"], attrs["protocol"]) elif name == "destination": for x in [ "ipv4", "ipv6" ]: if x in attrs: check_address(x, attrs[x]) if x in self.item.destination: log.warning("Destination address for '%s' already set, ignoring", x) else: self.item.destination[x] = attrs[x] elif name == "module": module = attrs["name"] if module.startswith("nf_conntrack_"): module = module.replace("nf_conntrack_", "") if "_" in module: module = module.replace("_", "-") if module not in self.item.modules: self.item.modules.append(module) else: log.warning("Module '%s' already set, ignoring.", module) elif name == "include": if attrs["service"] not in self.item.includes: self.item.includes.append(attrs["service"]) else: log.warning("Include '%s' already set, ignoring.", attrs["service"]) elif name == "helper": if attrs["name"] not in self.item.helpers: self.item.helpers.append(attrs["name"]) else: log.warning("Helper '%s' already set, ignoring.", attrs["name"]) def service_reader(filename, path): service = Service() if not filename.endswith(".xml"): raise FirewallError(errors.INVALID_NAME, "'%s' is missing .xml suffix" % filename) service.name = filename[:-4] service.check_name(service.name) service.filename = filename service.path = path service.builtin = False if path.startswith(config.ETC_FIREWALLD) else True service.default = service.builtin handler = service_ContentHandler(service) parser = sax.make_parser() parser.setContentHandler(handler) name = "%s/%s" % (path, filename) with open(name, "rb") as f: source = sax.InputSource(None) source.setByteStream(f) try: parser.parse(source) except sax.SAXParseException as msg: raise FirewallError(errors.INVALID_SERVICE, "not a valid service file: %s" % \ msg.getException()) del handler del parser if PY2: service.encode_strings() return service def service_writer(service, path=None): _path = path if path else service.path if service.filename: name = "%s/%s" % (_path, service.filename) else: name = "%s/%s.xml" % (_path, service.name) if os.path.exists(name): try: shutil.copy2(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) dirpath = os.path.dirname(name) if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath): if not os.path.exists(config.ETC_FIREWALLD): os.mkdir(config.ETC_FIREWALLD, 0o750) os.mkdir(dirpath, 0o750) f = io.open(name, mode='wt', encoding='UTF-8') handler = IO_Object_XMLGenerator(f) handler.startDocument() # start service element attrs = {} if service.version and service.version != "": attrs["version"] = service.version handler.startElement("service", attrs) handler.ignorableWhitespace("\n") # short if service.short and service.short != "": handler.ignorableWhitespace(" ") handler.startElement("short", { }) handler.characters(service.short) handler.endElement("short") handler.ignorableWhitespace("\n") # description if service.description and service.description != "": handler.ignorableWhitespace(" ") handler.startElement("description", { }) handler.characters(service.description) handler.endElement("description") handler.ignorableWhitespace("\n") # ports for port in service.ports: handler.ignorableWhitespace(" ") handler.simpleElement("port", { "port": port[0], "protocol": port[1] }) handler.ignorableWhitespace("\n") # protocols for protocol in service.protocols: handler.ignorableWhitespace(" ") handler.simpleElement("protocol", { "value": protocol }) handler.ignorableWhitespace("\n") # source ports for port in service.source_ports: handler.ignorableWhitespace(" ") handler.simpleElement("source-port", { "port": port[0], "protocol": port[1] }) handler.ignorableWhitespace("\n") # modules for module in service.modules: handler.ignorableWhitespace(" ") handler.simpleElement("module", { "name": module }) handler.ignorableWhitespace("\n") # destination if len(service.destination) > 0: handler.ignorableWhitespace(" ") handler.simpleElement("destination", service.destination) handler.ignorableWhitespace("\n") # includes for include in service.includes: handler.ignorableWhitespace(" ") handler.simpleElement("include", { "service": include }) handler.ignorableWhitespace("\n") # helpers for helper in service.helpers: handler.ignorableWhitespace(" ") handler.simpleElement("helper", { "name": helper }) handler.ignorableWhitespace("\n") # end service element handler.endElement('service') handler.ignorableWhitespace("\n") handler.endDocument() f.close() del handler PKpge[L2io/__pycache__/firewalld_conf.cpython-36.opt-1.pycnu[3 g5 @s~ddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddddd d d d d ddddg Z GdddeZdS)N)config)log)b2uu2bPY2 DefaultZone MinimalMark CleanupOnExitCleanupModulesOnExitLockdown IPv6_rpfilterIndividualCalls LogDeniedAutomaticHelpersFirewallBackendFlushAllOnReload RFC3964_IPv4AllowZoneDriftingc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)firewalld_confcCsi|_g|_||_|jdS)N)_config_deletedfilenameclear)selfrr$/usr/lib/python3.6/firewalld_conf.py__init__&szfirewalld_conf.__init__cCsi|_g|_dS)N)rr)rrrrr,szfirewalld_conf.clearcCs|jjg|_dS)N)rrr)rrrrcleanup0s zfirewalld_conf.cleanupcCs|jj|jS)N)rgetstrip)rkeyrrrr4szfirewalld_conf.getcCs8t|j}t|j|j|<||jkr4|jj|dS)N)rrrrremove)rr valueZ_keyrrrset7s  zfirewalld_conf.setcCsHd}x2|jjD]$\}}|r$|d7}|d||f7}qWtrDt|S|S)N z%s=%s)ritemsrr)rsr r"rrr__str__=s zfirewalld_conf.__str__cCs|jyt|jd}Wn8tk rR}ztjd|j||jdtj|jdt tj |jdtj rpdnd|jdtj rdnd|jd tj rdnd|jd tjrdnd|jd tjrdnd|jd tj|jd tj|jdtj|jdtjr dnd|jdtjr"dnd|jdtjr:dndWYdd}~XnXx|D]}|shP|j}t|dks\|dd.krq\dd|jdD}t|dkrtjd|jq\nr|dtkrtjd|jq\nN|ddkrtjd|jq\n*|jj|ddk r:tjd|jq\|d|j|d<q\W|j|jdstjdtj|jdt tj|jd}y t|WnPttfk r|dk rtj d |r|ndtj |jdt tj YnX|jd}| s|j!d/krJ|dk r2tj d#|r(|ndtj |jdtj rDdnd|jd}| sj|j!d0kr|dk rtj d$|r|ndtj |jdtj rdnd|jd }| s|j!d1kr|dk rtj d%|r|ndtj |jd tj rdnd|jd }| s"|j!d2kr^|dk rFtj d&|r<|ndtj|jd tjrXdnd|jd }| s~|j!d3kr|dk rtj d'|r|ndtj|jd tjrdnd|jd }| s|tj"kr|dk rtj d(|tj|jd t tj|jd }| s&|j!tj#kr\|dk rJtj d)|r@|ndtj|jd t tj|jd}| s~|j!tj$kr|dk rtj d*|r|ndtj|jdt tj|jd}| s|j!d4kr |dk rtj d+|r|ndtj|jdt tj|jd}| s*|j!d5kr`|dk rNtj d,|rD|ndtj|jdt tj|jd}| s|j!d6kr|dk rtj d-|r|ndtj|jdt tjdS)7NrzFailed to load '%s': %srrr yesnor r r r rrrrrrr#;cSsg|] }|jqSr)r).0xrrr bsz'firewalld_conf.read..=zInvalid option definition: '%s'zInvalid option: '%s'r$zMissing value: '%s'z!Duplicate option definition: '%s'z0DefaultZone is not set, using default value '%s'z7MinimalMark '%s' is not valid, using default value '%d'falsetruez7CleanupOnExit '%s' is not valid, using default value %sz>CleanupModulesOnExit '%s' is not valid, using default value %sz2Lockdown '%s' is not valid, using default value %sz7IPv6_rpfilter '%s' is not valid, using default value %sz9IndividualCalls '%s' is not valid, using default value %sz3LogDenied '%s' is invalid, using default value '%s'z:AutomaticHelpers '%s' is not valid, using default value %sz9FirewallBackend '%s' is not valid, using default value %sz:FlushAllOnReload '%s' is not valid, using default value %sz6RFC3964_IPv4 '%s' is not valid, using default value %sz;AllowZoneDrifting '%s' is not valid, using default value %s)r-r.)r+r4r*r5)r+r4r*r5)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)%ropenr Exceptionrerrorr#rZ FALLBACK_ZONEstrZFALLBACK_MINIMAL_MARKZFALLBACK_CLEANUP_ON_EXITZ FALLBACK_CLEANUP_MODULES_ON_EXITZFALLBACK_LOCKDOWNZFALLBACK_IPV6_RPFILTERZFALLBACK_INDIVIDUAL_CALLSZFALLBACK_LOG_DENIEDZFALLBACK_AUTOMATIC_HELPERSZFALLBACK_FIREWALL_BACKENDZFALLBACK_FLUSH_ALL_ON_RELOADZFALLBACK_RFC3964_IPV4ZFALLBACK_ALLOW_ZONE_DRIFTINGrlensplit valid_keysrrcloseint ValueError TypeErrorZwarninglowerZLOG_DENIED_VALUESZAUTOMATIC_HELPERS_VALUESZFIREWALL_BACKEND_VALUES)rfmsglineZpairr"rrrreadFs                                       zfirewalld_conf.readc :Cst|jdkrdSg}tjjtjs2tjtjdy.tj ddtjj |j tjj |j dd}Wn2t k r}ztjd|WYdd}~XnXd}d}ytj|j dd d }WnPt k r}z0tjj|j rtjd |j |fnd}WYdd}~Xn6Xx0|D]&}|sP|jd }t|dkrH|s2|jd d }n|ddkrpd}|j||jd n|jd}t|dkrd}|j|d q |dj} |dj} | |kr.| |jkr|j| | krd}|jd| |j| fd }n$| |jkrd }nd}|j|d |j| nd }q Wt|jdkrx^|jjD]P\} } | |krjqT| dkrxqT|s|jd d }|jd| | fd }qTW|r|j|j|stj|jdStjj|j r@ytj|j d|j WnBt k r>}z$tj|jtd|j |fWYdd}~XnXytj|j|j WnBt k r}z$tj|jtd|j |fWYdd}~XnXtj|j ddS)Nr,iZwtz%s.F)modeprefixdirdeletez!Failed to open temporary file: %sZrtzUTF-8)rFencodingzFailed to open '%s': %sr%Trr-r2r3z%s=%s rrz%s.oldzBackup of '%s' failed: %szFailed to create '%s': %si)rr) r:rospathexistsrZ ETC_FIREWALLDmkdirtempfileZNamedTemporaryFilebasenamerdirnamer7rr8ior6rwriter;rappendr&r=r!nameshutilZcopy2IOErrorZmovechmod) rdoneZ temp_filerCZmodifiedemptyrBrDpr r"rrrrSs                  $ $zfirewalld_conf.writeN) __name__ __module__ __qualname__rrrrr#r(rErSrrrrr%s r)Zos.pathrKrRrOrVZfirewallrZfirewall.core.loggerrZfirewall.functionsrrrr<objectrrrrrs  PKpge[)`/`/'io/__pycache__/io_object.cpython-36.pycnu[3 g5@sdZddddddddgZd d ljZd d ljjZd d lZd d lZd d lm Z d d l m Z d d l m Z d dl mZd dlmZejdkZGdddeZGdddeZGdddeZGdddeZGdddejjZGdddejZddZddZddZ ddZ!d S)z5Generic io_object handler, io specific check methods.PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol check_addressN) OrderedDict) functions)b2u)errors) FirewallError3c@s|eZdZdZfZdZgZiZiZddZ ddZ ddZ d d Z d d Z d dZddZddZddZddZddZdS)rz; Abstract IO_Object as base for icmptype, service and zone z()cCs"d|_d|_d|_d|_d|_dS)NF)filenamepathnamedefaultZbuiltin)selfr/usr/lib/python3.6/io_object.py__init__2s zIO_Object.__init__cCs6g}x(|jD]}|jtjt||dq Wt|S)Nr )IMPORT_EXPORT_STRUCTUREappendcopydeepcopygetattrtuple)rretxrrr export_config9s zIO_Object.export_configcCsXi}tdd|jD}x:|D]2}t||sAsz0IO_Object.export_config_dict..)dictrr isinstanceboolrr)rconf type_formatskeyrrrexport_config_dict?s  zIO_Object.export_config_dictcCs|j|xt|jD]~\}\}}t||tr~g}t}x,||D] }||krD|j||j|qDW~t||t j |qt||t j ||qWdS)N) check_config enumeraterr&listsetraddsetattrrr)rr(ielementZdummyZ_confZ_setr rrr import_configGs  zIO_Object.import_configc Cs~|j|xn|D]f}t||s0ttjdj|t||tr`t||tt j t j ||qt||t j ||qWdS)Nz-Internal error. '{}' is not a valid attribute) check_config_dicthasattrrr Z UNKNOWN_ERRORformatr&r.r1r fromkeysrr)rr(r*rrrimport_config_dictWs   "zIO_Object.import_config_dictcCszt|ts(ttjd|tdt|ft|dkr@ttjdx4|D],}|j rF||j krFttjd||fqFWdS)Nz'%s' not of type %s, but %srr"zname can't be emptyz'%s' is not allowed in '%s') r&strrr INVALID_TYPEtypelenZ INVALID_NAMEisalnumADDITIONAL_ALNUM_CHARS)rrcharrrr check_namecs     zIO_Object.check_namecCsjt|t|jkr0ttjdt|t|jfi}x&t|jD]\}\}}||||<q@W|j|dS)Nz structure size mismatch %d != %d)r=rrr r;r-r5)rr(Z conf_dictr2r yrrrr,pszIO_Object.check_configcCsrtdd|jD}xX|D]P}|dd|jDkrDttjdj||j|||||j||||qWdS)NcSsg|]}|d|dfqS)r r"r)r#r rrrr$|sz/IO_Object.check_config_dict..cSsg|] \}}|qSrr)r#r rBrrrr$~szoption '{}' is not valid)r%rrr ZINVALID_OPTIONr7_check_config_structure _check_config)rr(r)r*rrrr5{s  zIO_Object.check_config_dictcCsdS)Nr)rZdummy1Zdummy2Zdummy3rrrrDszIO_Object._check_configc Cs`t|t|s,ttjd|t|t|ft|trrt|dkrRttjd|x|D]}|j||dqXWnt|trt|t|krttjd|t|fxt |D]\}}|j|||qWnt|t r\t|j d\}}xn|j D]b\}}t|t|s,ttjd|t|t|ft|t|sttjd|t|t|fqWdS)Nz'%s' not of type %s, but %sr"zlen('%s') != 1r zlen('%s') != %d) r&r<rr r;r.r=rCrr-r%items) rr(Z structurer r2valueZskeyZsvaluer*rrrrCs8      z!IO_Object._check_config_structurecCs|j}d}||jkrdd}|j|dk rdx:|j|D],}||krL|j|q4ttjd||fq4W||jkrd}x$|j|D]}||kr~|j|q~W|sttjd|x |D]}ttjd||fqWdS)NFTzMissing attribute %s for %szUnexpected element %sz%s: Unexpected attribute %s)ZgetNamesPARSER_REQUIRED_ELEMENT_ATTRSremoverr Z PARSE_ERRORPARSER_OPTIONAL_ELEMENT_ATTRS)rrattrsZ_attrsfoundr rrrparser_check_element_attrss,     z$IO_Object.parser_check_element_attrsN)__name__ __module__ __qualname____doc__rZDBUS_SIGNATUREr?rGrIrr!r+r4r9rAr,r5rDrCrLrrrrr)s"   !cs$eZdZfddZddZZS)UnexpectedElementErrorcstt|j||_dS)N)superrQrr)rr) __class__rrrszUnexpectedElementError.__init__cCs d|jS)NzUnexpected element '%s')r)rrrr__str__szUnexpectedElementError.__str__)rMrNrOrrT __classcell__rr)rSrrQs rQcs$eZdZfddZddZZS)MissingAttributeErrorcstt|j||_||_dS)N)rRrVrr attribute)rrrW)rSrrrszMissingAttributeError.__init__cCsd|j|jfS)Nz$Element '%s': missing '%s' attribute)rrW)rrrrrTszMissingAttributeError.__str__)rMrNrOrrTrUrr)rSrrVs rVcs$eZdZfddZddZZS)UnexpectedAttributeErrorcstt|j||_||_dS)N)rRrXrrrW)rrrW)rSrrrsz!UnexpectedAttributeError.__init__cCsd|j|jfS)Nz'Element '%s': unexpected attribute '%s')rrW)rrrrrTsz UnexpectedAttributeError.__str__)rMrNrOrrTrUrr)rSrrXs rXc@s4eZdZddZddZddZddZd d Zd S) rcCs||_d|_dS)Nr)item_element)rrYrrrrsz!IO_Object_ContentHandler.__init__cCs d|_dS)Nr)rZ)rrrr startDocumentsz&IO_Object_ContentHandler.startDocumentcCs d|_dS)Nr)rZ)rrrJrrr startElementsz%IO_Object_ContentHandler.startElementcCs*|dkr|j|j_n|dkr&|j|j_dS)Nshort description)rZrYr]r^)rrrrr endElements z#IO_Object_ContentHandler.endElementcCs|j|jdd7_dS)N  )rZreplace)rcontentrrr characterssz#IO_Object_ContentHandler.charactersN)rMrNrOrr[r\r_rdrrrrrs c@s<eZdZddZddZddZddZd d Zd d Zd S)rcCsNtjjj||j|_|j|_ig|_|jd|_ g|_ d|_ d|_ d|_ dS)Nr"zutf-8F)saxhandlerContentHandlerrwrite_writeflushZ_flushZ _ns_contextsZ_current_contextZ_undeclared_ns_mapsZ _encodingZ_pending_start_elementZ_short_empty_elements)routrrrrs zIO_Object_XMLGenerator.__init__cCs*trdd|jD}tjj|||dS)a saxutils.XMLGenerator.startElement() expects name and attrs to be unicode and bad things happen if any of them is (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. cSsi|]\}}t|t|qSr)r )r#rrFrrr sz7IO_Object_XMLGenerator.startElement..N)rrEsaxutils XMLGeneratorr\)rrrJrrrr\sz#IO_Object_XMLGenerator.startElementcCstrX|jdt|x4|jD](\}}|jdt|tjt|fq W|jdnF|jd|x,|jD] \}}|jd|tj|fqpW|jddS)z* slightly modified startElement() N)rrjr rErnZ quoteattr)rrrJrFrrr simpleElements  z$IO_Object_XMLGenerator.simpleElementcCstjj|t|dS)z saxutils.XMLGenerator.endElement() expects name to be unicode and bad things happen if it's (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. N)rnror_r )rrrrrr_sz!IO_Object_XMLGenerator.endElementcCstjj|t|dS)z saxutils.XMLGenerator.characters() expects content to be unicode and bad things happen if it's (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. N)rnrordr )rrcrrrrd%sz!IO_Object_XMLGenerator.characterscCstjj|t|dS)a saxutils.XMLGenerator.ignorableWhitespace() expects content to be unicode and bad things happen if it's (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. N)rnroignorableWhitespacer )rrcrrrrr-sz*IO_Object_XMLGenerator.ignorableWhitespaceN) rMrNrOrr\rqr_rdrrrrrrrs  cCstj|}|dkr$ttjd|n`|dkr>ttjd|nF|dkrXttjd|n,t|dkr|d|dkrttjd|dS) Nzport number in '%s' is too bigr"z'%s' is invalid port rangezport range '%s' is ambiguousr re)r Z getPortRangerr Z INVALID_PORTr=)ZportZ port_rangerrrr5s    cCs|dkrttjd|dS)Ntcpudpsctpdccpz)'%s' not from {'tcp'|'udp'|'sctp'|'dccp'})rurvrwrx)rr INVALID_PROTOCOL)protocolrrrrDscCstj|sttj|dS)N)r Z checkProtocolrr ry)rzrrrrJs cCs$tj||s ttjd||fdS)Nz'%s' is not valid %s address)r rrr Z INVALID_ADDR)ZipvZaddrrrrrNs )"rP__all__Zxml.saxrfZxml.sax.saxutilsrnrsys collectionsr Zfirewallr Zfirewall.functionsr r Zfirewall.errorsrversionrobjectr ExceptionrQrVrXrgrhrrorrrrrrrrrs0           CPKpge[͆ RR$io/__pycache__/policy.cpython-36.pycnu[3 gϢ@s dddgZddljZddlZddlZddlZddlmZddlm Z m Z ddlm Z m Z m Z ddlmZmZmZdd lmZmZmZmZmZmZdd lmZdd lmZdd lmZdd lmZddZ ddZ!ddZ"ddZ#ddZ$GdddeZ%GdddeZ&dddZ'dddZ(dS) Policy policy_reader policy_writerN)config)checkIPcheckIP6)uniqifymax_policy_name_lenportStr)DEFAULT_POLICY_TARGETPOLICY_TARGETSDEFAULT_POLICY_PRIORITY) IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol)rich)log)errors) FirewallErrorc Cs|dkr n|dkrn|dkr|jr`|jjrJtjdt|jd|_dStj|d|j_dS|d|jj kr|jj j |dntjd|dn|dkrN|jr|jjrtjdt|jd|_dStj |d|d |j_dSt |dt |d t|dd |d f}||jjkr4|jjj |ntjd |d|d nN|d kr|jr|jjrtjdt|jd|_dStj|d |j_nBt|d |d |jjkr|jjj |d ntjd |d n|dkrh|jr.|jjrtjdt|jd|_dStj|d|j_dS|d|jjkrT|jjj |dntjd|dn4|dkr|jr|jjrtjdt|jd|_dStj|d|j_dStjd|dn|dkr2|jr|jjrtjdt|jd|_dStj|j_n|jjr&tjdnd|j_nj|dkrd}d|krR|d}d}d|krh|d}|jr|jjrtjdt|jd|_dStj|d|d |||j_dSt |dt |d |rt ||r t| r t| r ttjd|t|dd |d t|d t|f}||jjkrL|jjj |n6tjd|d|d |rld|nd|r|d|ndn|dkr@|jr|jjrtjdt|jd|_dStj|d|d |j_dSt |dt |d t|dd |d f}||jj kr&|jj j |ntjd|d|d n\|dkr|jsftjdd|_dS|jj!rtjd t|jdSd!}d}d"|kr|d"}d}d#|kr|d#}d$|kr|d$j"dLkrd}tj#||||j_!n|dMkr|jstjd+d|_dS|jj$r0tjd,d|_dS|d'krHtj%|j_$nh|d(krxd} d-|krh|d-} tj&| |j_$n8|d)krtj'|j_$n |d*kr|d.} tj(| |j_$|jj$|_)n|d/kr^|jstjd0dS|jjrtjd1dSd} d2|kr*|d2} | dNkr*tjd;d|_dSd<|kr<|d<nd} tj*| | |j_|jj|_)n>|d=kr|js~tjd>dS|jj+rtjd?t|jd|_dStj,|j_+|jj+|_)n|d@kr,d} dA}dB|kr|dB} | dOkrtjdE|dBd|_dSdF|krt-|dF}tj.| |dG|_np|dHkr|j)sRtjdId|_dS|j)j/rxtjdJt|jd|_dS|d }tj0||j1dK|j)_/nd!SdS)PNshort descriptionservicez;Invalid rule: More than one element in rule '%s', ignoring.Tnamez#Service '%s' already set, ignoring.portprotocol-z#Port '%s/%s' already set, ignoring.valuez$Protocol '%s' already set, ignoring.z icmp-blockz&icmp-block '%s' already set, ignoring.z icmp-typez-Invalid rule: icmp-block '%s' outside of rule masqueradez!Masquerade already set, ignoring.z forward-portzto-portzto-addrz#to-addr '%s' is not a valid addressz-Forward port %s/%s%s%s already set, ignoring.z >%sz @%sz source-portz*Source port '%s/%s' already set, ignoring. destinationz)Invalid rule: Destination outside of rulez?Invalid rule: More than one destination in rule '%s', ignoring.Faddressipsetinvertyestrueacceptrejectdropmarkz$Invalid rule: Action outside of rulez"Invalid rule: More than one actiontypesetrz!Invalid rule: Log outside of rulezInvalid rule: More than one loglevelemergalertcriterrorwarningnoticeinfodebugzInvalid rule: Invalid log levelprefixauditz#Invalid rule: Audit outside of rulez9Invalid rule: More than one audit in rule '%s', ignoring.rulerfamilyipv4ipv6z&Invalid rule: Rule family "%s" invalidpriority)r:r=limitz4Invalid rule: Limit outside of action, log and auditz9Invalid rule: More than one limit in rule '%s', ignoring.burst)r&r')r(r)r*r+)r/r0r1r2r3r4r5r6)r;r<)2_ruleelementrr3str _rule_errorr Rich_Serviceitemservicesappend Rich_Portrrr ports Rich_Protocolr protocolsRich_IcmpBlock icmp_blocks Rich_IcmpTypeRich_Masquerader Rich_ForwardPortrrrr INVALID_ADDR forward_portsRich_SourcePort source_portsr"lowerZRich_Destinationaction Rich_Accept Rich_Reject Rich_Drop Rich_Mark _limit_okZRich_Logr8Z Rich_Auditint Rich_Ruler>Z Rich_Limitget)objrattrsentryto_portZto_addrr%r#r$Z_typeZ_setr.r7r:r=rrc/usr/lib/python3.6/policy.pycommon_startElements                                                                            recCs|dkr|jsy|jjWn6tk rR}ztjd|t|jWYdd}~XnLXt|j|jjkr|jj j |j|jjj t|jntjdt|jd|_d|_n|d krd|_ dS) Nr9z%s: %sz Rule '%s' already set, ignoring.Fr(r)r*r+rr8)r(r)r*r+rr8) rCr@Zcheck Exceptionrr3rBrE rules_strrulesrGr[)r_rercrcrdcommon_endElements& rjcCst|trdnd}|dkrT|jrT|jj}x$|D]}||kr0ttjd|q0Wn|dkrx$|D]}t|dt|dqbWnb|dkrx|D] }t |qWn@|d kr|jr|jj } x$|D]} | | krttj d | qWn|d krx|D]} t| dt| d| d  r>| d  r>ttj d| | d rTt| d | d rt | d  rt| d  rttjd| d qWnT|dkrx&|D]}t|dt|dqWn|dkrx|D]} tj| d} |jr| jrt| jtjst| jtjr|jj } | jj| krLttj d | jjnH| jr|jj| jj}|jr| j|jkrttj d| j| jjfnL|jrt| jtjr|jj}| jj|krttjdj||j| jjqWdS)NrZZonerFz '%s' not among existing servicesrIrrKrMz"'%s' not among existing icmp typesrRz$'%s' is missing to-port AND to-addr z#to-addr '%s' is not a valid addressrTrg rich_rules)rule_strz3rich rule family '%s' conflicts with icmp type '%s'z){} '{}': '{}' not among existing services)rgrn) isinstancer fw_configZ get_servicesrrZINVALID_SERVICErrrZ get_icmptypesZINVALID_ICMPTYPEINVALID_FORWARDrrrQrr]rArLrNrr:Z get_icmptyper"rDformat)r_rrE all_configZobj_typeZexisting_servicesrrprotoZexisting_icmptypesZicmptypefwd_portr9Zobj_richZictrcrcrdcommon_check_config2s                      rwcCs0d|ji}|j}|dk r ||d<|jd|dS)Nrr?r>)rr? simpleElement)handlerr>dr?rcrcrd_handler_add_rich_limitxs  r{c Cs|jrF|jdkrF|jd|jdi|j|j|jd|jd|jr|jdkr|jd|jdi|j|j|jd|jdx6t|jD](}|jd|jdd|i|jdqWx@t|j D]2}|jd|jd|d |d d |jdqWx8t|j D]*}|jd|jd d |i|jdqWx8t|j D]*}|jd|jdd|i|jdqLW|j r|jd|jdi|jdxt|j D]}|jd|d |d d }|dr|ddkr|d|d<|dr|ddkr|d|d<|jd||jdqWxBt|jD]4}|jd|jd|d |d d |jdq>WxT|jD]H}i}|jr|j|d<|jd krt|j|d<|jd|jd||jd|jrVi}|jjr|jj|d<|jjr|jj|d<|jjr$|jj|d<|jjr6d|d<|jd|jd||jd|jri}|jjrx|jj|d<|jjr|jj|d<|jjrd|d<|jd|jd ||jd|jrxd} i}t|jtjkrd} |jj|d<nbt|jtjkr(d} |jj|d<|jj |d <n0t|jtj!krNd } |jj"|d <n t|jtj#krfd} nt|jtj$krd} |jj|d<nt|jtj%krd!} |jj|d<nt|jtj&krd} |jj|d<|jj |d <|jj'dkr|jj'|d<|jj(dkrX|jj(|d<nFt|jtj)krBd} |jj|d<|jj |d <nt*t+j,d"t|j|jd|j| ||jd|j-ri}|j-j.r|j-j.|d#<|j-j/r|j-j/|d$<|j-j0r|jd|jd%||jd&t1||j-j0|jd'|jd%n|jd|jd%||jd|j2ri}|j2j0rx|jd|jd(i|jd&t1||j2j0|jd'|jd(n|jd|jd(||jd|j3rd} i}t|j3tj4krd)} n|t|j3tj5krd*} |j3jr<|j3j|d+<nNt|j3tj6krd,} n6t|j3tj7kr*d-} |j3j8|d.<nt-j9d/t|j3|j3j0r|jd|j| ||jd&t1||j3j0|jd'|j| n|jd|j| ||jd|jd|jd|jdqWdS)0Nr!z r rrrrrrk)rrrrz icmp-blockr rlzto-portrmzto-addrz forward-portz source-portr:r=r9r#macr$Truer%z sourcer"z icmp-typez"Unknown element '%s' in obj_writerr7r.rz z r8r(r)r,r*r+r-zUnknown action '%s'):rignorableWhitespace startElementZ characters endElementrrrFrxrIrKrMr rRrTrhr:r=rBraddrr}r$r%r"rAr,rrDrrHrrrJrrOrLrNrPrb to_addressrSrrZINVALID_OBJECTrr7r.r>r{r8rVrWrXrYrZr-r3) r_ryrrrZicmpZforwardr`r9rArVrcrcrd common_writers\                                                                                        rcsPeZdZd7ZdZeZdgZd8d9d:d;d dgfd dgfddgfddgfdd?gfd@ddgfddgffZdddgZ dddgdgddgdgdgdddgddddgddgddddddgdgdgdgdZ ddgdd gd!dgd"d#d$d!d%gd"d$d%gd&d'gd(gd)gd*Z fd+d,Z d-d.Z fd/d0Zfd1d2Zd3d4Zfd5d6ZZS)Ariirversionr!rrtargetrFrIrMr FrRrnrKrTr= ingress_zones egress_zones_r/Nrrrrr-)rrpolicyrrz icmp-blockz icmp-typer z forward-portr9rr"rz source-portrr8r(r)r*r+r>z ingress-zonez egress-zonezto-portzto-addrr:r#r}r%r$r7r.r,r?)rz forward-portr9rr"rr)r>cstt|jd|_d|_d|_t|_g|_g|_ g|_ g|_ d|_ g|_ g|_d|_g|_g|_d|_|j|_d|_g|_g|_dS)Nr!F)superr__init__rrrr rrFrIrKrMr rRrTrqrhrgappliedpriority_defaultr=Zderived_from_zonerr)self) __class__rcrdrs(zPolicy.__init__cCsd|_d|_d|_t|_|jdd=|jdd=|jdd=|jdd=d|_ |j dd=|j dd=d|_ |j dd=|jdd=d|_|j|_|jdd=|jdd=dS)Nr!F)rrrr rrFrIrKrMr rRrTrqrhrgrrr=rr)rrcrcrdcleanups$         zPolicy.cleanupcs"|dkr|jSttt||SdS)Nrn)rggetattrrr)rr)rrcrd __getattr__szPolicy.__getattr__csB|dkr,dd|D|_dd|jD|_ntt|j||dS)NrncSsg|]}tj|dqS))ro)rr]).0srcrcrd sz&Policy.__setattr__..cSsg|] }t|qSrc)rB)rrrcrcrdrs)rhrgrr __setattr__)rrr)rrcrdrszPolicy.__setattr__c Cst|||||dkr2|tkr.ttjd|n|dkrz||jksX||jksX||jkrvttjd||j|j|jfn|dkrhddg}|j r||j j 7}x|D]}||krttj d ||dkrt ddgt |@s|dkrt |t |grttj d ||dkr|dkr8d|kr8d|dksT|dkrd|krd|dkrttj d qWn|d kr|rd|krd|dkrttj d nxd|krd|dkrttj dxR|dD]F}|dkrސq|j j |}|j rd|j j|krttj dqWn|dkr4x|D]}tj|d}|jrt|jtjrd|kr|d|dkr|ttj d nxd|kr,d|dkrttj dxR|dD]F}|dkrq|j j |}|j rd|j j|krttj dqWq,|jrt|jtjrd|kr,d|dkr@|jjrttjdnt|dr,|jjs`ttjdd|dkr,x|dD]8}|j j |}|j rxd|j j|krxttj dqxWnv|jr,t|jtjr,d|kr,xR|dD]F}|dkrq|j j |}|j rd|j j|krttj dqWq,Wn|dkrx|D]} d|krnd|dkrnttj dnd|krDd|dkr| drttjdnt|drD| dsttjdd|dkrDxD|dD]8}|j j |}|j rd|j j|krttj dqWqDWdS)Nrz'%s' is invalid targetr=zQ%d is invalid priority. Must be in range [%d, %d]. The following are reserved: %srrANYHOSTz'%s' not among existing zonesz>'%s' may only contain one of: many regular zones, ANY, or HOSTzF'HOST' can only appear in either ingress or egress zones, but not bothr z.'masquerade' is invalid for egress zone 'HOST'z/'masquerade' is invalid for ingress zone 'HOST'Z interfaceszR'masquerade' cannot be used in a policy if an ingress zone has assigned interfacesrn)rozAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zonezS'forward-port' cannot be used in a policy if an egress zone has assigned interfaceszR'mark' action cannot be used in a policy if an egress zone has assigned interfacesrRz1'forward-port' is invalid for ingress zone 'HOST'rm)rr)rr)rr)rr)rwr rrINVALID_TARGETpriority_reserved priority_max priority_minZINVALID_PRIORITYrq get_zonesZ INVALID_ZONEr-Zget_zoneZget_zone_config_dictrr]rArprOrPrrrrVrZ) rrrErtZexisting_zoneszoneZz_objr9r_rvrcrcrd _check_configs       "                           zPolicy._check_configcstt|j||jdr,ttjd|n|jdrHttjd|n|jddkrhttjd|njd|kr|d|j d}n|}t |t krttjd|t |t f|j r||j j krttjddS)Nrz'%s' can't start with '/'z'%s' can't end with '/'rkzmore than one '/' in '%s'z&Policy of '%s' has %d chars, max is %dz,Policies can't have the same name as a zone.)rr check_name startswithrr INVALID_NAMEendswithcountfindlenr rqrZ NAME_CONFLICT)rrZ checked_name)rrcrdr,s*      zPolicy.check_namei)rr!)rr!)rr!)rr!)r!r!)r F)r!r!r!r!)r!r!)r=r)__name__ __module__ __qualname__rrr rrZIMPORT_EXPORT_STRUCTUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrrrrrr __classcell__rcrc)rrdrZsr        ^c@s$eZdZddZddZddZdS)policy_ContentHandlercCs"tj||d|_d|_d|_dS)NF)rrr@rCr[)rrErcrcrdrHs zpolicy_ContentHandler.__init__cCstj||||jrdS|jj||t|||r6dS|dkrd|krR|d|j_d|krjt|d|j_d|kr|d}|t krt t j ||r||j_ n^|dkr|d|jjkr|jjj|dntjd|dn|dkr |d|jjkr|jjj|dntjd |dn|d kr|jsFtjd d |_dS|jjrltjd t|jd |_dSd}d|kr|djdkrd }d}}}d|kr|d}d|kr|d}d|kr|d}tj||||d|j_dStjd|dSdS)Nrrr=rz ingress-zonerz(Ingress zone '%s' already set, ignoring.z egress-zonez'Egress zone '%s' already set, ignoring.rz$Invalid rule: Source outside of ruleTz:Invalid rule: More than one source in rule '%s', ignoring.Fr%r&r'r#r}r$)r%zUnknown XML element '%s')r&r')rrrCrEZparser_check_element_attrsrerr\r=r rrrrrrGrr3rr@rrBrUrZ Rich_Source)rrr`rr%rr}r$rcrcrdrNsf                 z"policy_ContentHandler.startElementcCstj||t||dS)N)rrrj)rrrcrcrdrs z policy_ContentHandler.endElementN)rrrrrrrcrcrcrdrGs@rFc Cst}|jds ttjd||dd |_|s>|j|j||_||_|j t j rZdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r} zttjd| jWYdd} ~ XnXWdQRX~~|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid policy file: %s)rrrrrrrfilenamepathrr ETC_FIREWALLDZbuiltindefaultrsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_POLICYZ getException) rrZ no_check_namerryparserrfrmsgrcrcrdrs6        (c Cs|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|j|jkr0t|j|d <|j|d <|jd ||jdt||x8t|jD]*} |jd|jdd| i|jdqfWx8t|jD]*} |jd|jdd| i|jdqW|jd |jd|j |j!~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingr!rr=rrr|z z ingress-zonerz egress-zone)"rrrosexistsshutilZcopy2rfrr2dirnamerrrmkdiriorrZ startDocumentrr=rrBrrrrrrrxrrZ endDocumentclose) rr_pathrrdirpathrryr`rrcrcrdrsN             )F)N))__all__Zxml.saxrrrrZfirewallrZfirewall.functionsrrrr r Zfirewall.core.baser r r Zfirewall.core.io.io_objectrrrrrrZ firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrerjrwr{rrrrrrcrcrcrds4        F[nL PKpge[r))*io/__pycache__/helper.cpython-36.opt-1.pycnu[3 g @sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)Helper helper_reader helper_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudp)log)errors) FirewallErrorcseZdZddddddd gffZdZd d gZd d dgd Zd ddgddgdZfddZddZ ddZ ddZ ddZ Z S)!rversionshort descriptionfamilymoduleportsz (sssssa(ss))-.N)rrhelpernameportprotocol)rrcs6tt|jd|_d|_d|_d|_d|_g|_dS)Nr) superr__init__rrrrrr)self) __class__/usr/lib/python3.6/helper.pyr;szHelper.__init__cCs.d|_d|_d|_d|_d|_|jdd=dS)Nr)rrrrrr)rr!r!r"cleanupDs zHelper.cleanupcCsRt|j|_t|j|_t|j|_t|j|_t|j|_dd|jD|_dS)z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSs g|]\}}t|t|fqSr!)r).0ZpoZprr!r!r" Usz)Helper.encode_strings..N)rrrrrrr)rr!r!r"encode_stringsLs      zHelper.encode_stringscCs(ddg}||kr$ttjd||fdS)NZipv4Zipv6z'%s' not in '%s')rrZ INVALID_IPV)rZipvZipvsr!r!r" check_ipvWszHelper.check_ipvcCsz|dkr0xl|D]}t|dt|dqWnF|dkrv|jdsRttjd|t|jdddkrvttjd|dS) Nrrr nf_conntrack_z('%s' does not start with 'nf_conntrack_'rzModule name '%s' too short)r r startswithrrINVALID_MODULElenreplace)rritemZ all_configrr!r!r" _check_config]s    zHelper._check_config)rr)rr)rr)rr)rr)rr)__name__ __module__ __qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr#r&r'r/ __classcell__r!r!)r r"r&s$     c@seZdZddZdS)helper_ContentHandlercCs>tj||||jj|||dkrd|kr8|d|j_d|kr\|jj|d|d|j_d|kr|djdstt j d|dt |dj dddkrtt j d |d|d|j_ nz|d krnp|d krnf|d kr:t|d t|d |d |d f}||jjkr$|jjj|ntjd|d |d dS)Nrrrrr)z('%s' does not start with 'nf_conntrack_'rr(zModule name '%s' too shortrrrrz#Port '%s/%s' already set, ignoring.)r startElementr.Zparser_check_element_attrsrr'rr*rrr+r,r-rr r rappendr Zwarning)rrattrsentryr!r!r"r5ns>      z"helper_ContentHandler.startElementN)r0r1r2r5r!r!r!r"r4msr4c Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid helper file: %s)rendswithrrZ INVALID_NAMErZ check_namefilenamepathr*r ETC_FIREWALLDZbuiltindefaultr4saxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_HELPERZ getExceptionrr&) r=r>rhandlerparserrfsourcemsgr!r!r"rs8        (c CsP|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|j|d <|jr|jd kr|j|d <|jr<|jd kr<|j|d <|jd ||jd|jr|jd kr|jd|jdi|j|j|jd|jd|jr|jd kr|jd|jdi|j|j|jd|jdx>|jD]4} |jd|jd| d| dd|jdqW|jd |jd|j|j~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrrrr z rrrrr()rr) r>r=rosexistsshutilZcopy2 Exceptionr errordirnamer*rr?mkdiriorBr Z startDocumentrrrr5ZignorableWhitespacerZ charactersZ endElementrrZ simpleElementZ endDocumentclose) rr>_pathrrHdirpathrFrDr7rr!r!r"rs\                       )N)__all__Zxml.saxrArLrSrNZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr r r r Zfirewall.core.loggerr rZfirewall.errorsrrr4rrr!r!r!r"s        G#PKpge[m&io/__pycache__/__init__.cpython-36.pycnu[3 g<@sjddlZdejkrfddlmZeedss      PKpge[V..*io/__pycache__/direct.cpython-36.opt-1.pycnu[3 g=@sddljZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddl mZmZmZddlmZddlmZddlmZdd lmZdd lmZGd d d eZGd ddeZdS)N)config)LastUpdatedOrderedDict) splitArgsjoinArgs u2b_if_py2) IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log) ipXtables)ebtables)errors) FirewallErrorc@s$eZdZddZddZddZdS)direct_ContentHandlercCstj||d|_dS)NF)r__init__direct)selfitemr/usr/lib/python3.6/direct.pyr(s zdirect_ContentHandler.__init__c Cstj||||jj|||dkr@|jr6ttjdd|_n>|dkr|js\tj ddS|d}|d}|d}|jj t |t |t |n|dkr6|jstj d dS|d}|dkrttj d ||d}|d}yt |d}Wn(tk rtj d|ddSXt |t |t ||g|_nH|dkrl|jsVtj ddS|d}t |g|_ntj d|dSdS)NrzMore than one direct tag.Tchainz$Parse Error: chain outside of directipvtablerulez#Parse Error: rule outside of directipv4ipv6ebz"'%s' not from {'ipv4'|'ipv6'|'eb'}priorityz'Parse Error: %s is not a valid priority passthroughz&Parse Error: command outside of directzUnknown XML element %s)rrr)r startElementrZparser_check_element_attrsrrr Z PARSE_ERRORr error add_chainr INVALID_IPVint ValueError_rule _passthrough)rnameZattrsrrrrrrrr,sT          z"direct_ContentHandler.startElementcCstj|||dkrX|jrF|jjddt|jD|jj|jn tj dd|_nJ|dkr|jr|j jddt|jD|jj |j n tj d d|_ dS) NrcSsg|] }t|qSr)r).0xrrr dsz4direct_ContentHandler.endElement..z2Error: rule does not have any arguments, ignoring.rcSsg|] }t|qSr)r)r(r)rrrr*msz0Error: passthrough does not have any arguments, z ignoring.z9Error: passthrough does not have any arguments, ignoring.) r endElementZ_elementr%appendrradd_ruler r r&add_passthrough)rr'rrrr+^s     z direct_ContentHandler.endElementN)__name__ __module__ __qualname__rrr+rrrrr's2rcs<eZdZdZddBgfddddddgfgfdddgfgffZdZdd d d gd d d d gd gd ZiZfddZddZ ddZ ddZ ddZ ddZ ddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z d@dAZ!Z"S)CDirectz Direct class chainsrulesr passthroughsz(a(sss)a(sssias)a(sas))Nrrrr)rrrrcs0tt|j||_t|_t|_t|_dS)N)superr2rfilenamerr3r5r6)rr8) __class__rrrs zDirect.__init__cCsdS)Nr)rconfrZall_confrrr _check_configszDirect._check_configc Csg}g}x>|jD]4}x.|j|D] }|jtt|t|gq WqW|j|g}xR|jD]H}xB|j|D]4}|jt|d|d|d|dt|dfqnWq^W|j|g}x8|jD].}x(|j|D]}|jt|t|fqWqW|j|t|S)Nr)r3r,tuplelistr5r6)rretr)keyrrrrr export_configs$ $     zDirect.export_configcCs|j|j|xt|jD]x\}\}}|dkrNx||D]}|j|qr rRrL)rrrrrrMrAvaluerrrr-s     zDirect.add_rulecCs|j|||||f}|t|f}||jkrb||j|krb|j||=t|j|dkr|j|=n$tddj|||fd||fdS)Nrz(Rule '%s' for table '%s' and chain '%s' z',z)with ipv '%s' and priority %d not in list)rQr>r5rTr$rL)rrrrrrMrArYrrr remove_rules     zDirect.remove_rulecCsb|j|||||f}||jkr^x"|j|jD]}|j||=q0Wt|j|dkr^|j|=dS)Nr)rQr5rPrT)rrrrrArYrrr remove_rules"s   zDirect.remove_rulescCs:|j|||||f}|t|f}||jko8||j|kS)N)rQr>r5)rrrrrrMrArYrrr query_rule+s   zDirect.query_rulecCsF|j|||||f}||jkr*|j|Std||fd|dS)Nz'No rules for table '%s' and chain '%s' z with ipv '%s')rQr5r$)rrrrrArrr get_rules1s     zDirect.get_rulescCs|jS)N)r5)rrrr get_all_rules:szDirect.get_all_rulescCs^|j|||jkrg|j|<||j|kr>|j|j|ntjddj||fddS)NzPassthrough '%s' for ipv '%s'z',zalready in list, ignoring)rOr6r,r rRrL)rrrMrrrr.?s   zDirect.add_passthroughcCsl|j|||jkrN||j|krN|j|j|t|j|dkrh|j|=ntddj||fddS)NrzPassthrough '%s' for ipv '%s'z',z not in list)rOr6rSrTr$rL)rrrMrrrremove_passthroughIs  zDirect.remove_passthroughcCs"|j|||jko ||j|kS)N)rOr6)rrrMrrrquery_passthroughSs zDirect.query_passthroughcCs.|j|||jkr|j|Std|dS)NzNo passthroughs for ipv '%s')rOr6r$)rrrrrget_passthroughsWs   zDirect.get_passthroughscCs|jS)N)r6)rrrrget_all_passthroughs^szDirect.get_all_passthroughscCs|j|jjds&ttjd|jt|}tj}|j |t |jdb}tj d}|j |y|j |Wn8tjk r}zttjd|jWYdd}~XnXWdQRXdS)Nz.xmlz'%s' is missing .xml suffixrbzNot a valid file: %s)rCr8endswithrr Z INVALID_NAMErsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZ INVALID_TYPEZ getException)rhandlerparserfsourcemsgrrrreadcs      z Direct.readc CsBtjj|jr\ytj|jd|jWn4tk rZ}ztd|j|fWYdd}~XnXtjjtj sxtj tj dt j |jddd}t |}|j|jdi|jdxR|jD]H}|\}}x:|j|D],}|jd |jd |||d |jdqWqWx|jD]}|\}}}xx|j|D]j\}} t| d kr@q&|jd |jd |||d|d|jtjjt| |jd |jdq&Wq Wx||jD]r}xj|j|D]\} t| d krȐq|jd |jdd|i|jtjjt| |jd|jdqWqW|jd|jd|j|j~dS)Nz%s.oldzBackup of '%s' failed: %siZwtzUTF-8)modeencodingr z r)rrrr<rz%d)rrrrrr)ospathexistsr8shutilZcopy2 ExceptionIOErrorrZ ETC_FIREWALLDmkdiriorfr Z startDocumentrZignorableWhitespacer3Z simpleElementr5rTreZsaxutilsescaperr+r6Z endDocumentclose) rrlrjrhrArrrrrMrrrwriteusZ$                z Direct.write)r4r4r4)#r/r0r1__doc__rEZDBUS_SIGNATUREZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr;rBrHrCrNrOrQr!rUrVrWrXr-rZr[r\r]r^r.r_r`rarbrmr{ __classcell__rr)r9rr2usH            r2)Zxml.saxrerqrxrtZfirewallrZfirewall.fw_typesrZfirewall.functionsrrrZfirewall.core.io.io_objectrrr Zfirewall.core.loggerr Z firewall.corer r r Zfirewall.errorsrrr2rrrrs        NPKpge[m,io/__pycache__/__init__.cpython-36.opt-1.pycnu[3 g<@sjddlZdejkrfddlmZeedss      PKpge[*;]q 'io/__pycache__/functions.cpython-36.pycnu[3 gy@sddlZddlmZddlmZddlmZddlmZddl m Z ddl m Z ddl mZdd lmZdd lmZdd lmZdd lmZdd lmZddZdS)N)config) FirewallError)FirewallConfig) zone_reader)service_reader) ipset_reader)icmptype_reader) helper_reader) policy_reader)Direct)LockdownWhitelist)firewalld_confc -Cs|t|}t|jtjtjgdt|jtjtj gdt |j tj tj gdt|jtjtjgdt|jtjtjgdt|jtjtjgdd}x |jD]}x||dD]}tjj|sqxttj|D]}|j dryD||d||}|d kr||_!|j"|j#||d|Wqt$k rT}zt$|j%d ||j&fWYdd}~Xqt'k r}zt'd ||fWYdd}~XqXqWqWqWtjj(tj)r:y$t*tj)}|j+|j,|j-Wnpt$k r}zt$|j%d tj)|j&fWYdd}~Xn6t'k r8}zt'd tj)|fWYdd}~XnXtjj(tj.ry$t/tj.}|j+|j,|j-Wnpt$k r}zt$|j%d tj.|j&fWYdd}~Xn6t'k r}zt'd tj.|fWYdd}~XnXtjj(tj0rxyt1tj0}|j+Wnpt$k rB}zt$|j%d tj0|j&fWYdd}~Xn6t'k rv}zt'd tj0|fWYdd}~XnXdS) N)readeradddirs)ZipsethelperZicmptypeZservicezonepolicyrz.xmlrrrrz'%s': %s)rr)2rrZ add_ipsetrZFIREWALLD_IPSETSZETC_FIREWALLD_IPSETSr Z add_helperZFIREWALLD_HELPERSZETC_FIREWALLD_HELPERSrZ add_icmptypeZFIREWALLD_ICMPTYPESZETC_FIREWALLD_ICMPTYPESrZ add_serviceZFIREWALLD_SERVICESZETC_FIREWALLD_SERVICESrZadd_zoneZFIREWALLD_ZONESZETC_FIREWALLD_ZONESr Zadd_policy_objectZFIREWALLD_POLICIESZETC_FIREWALLD_POLICIESkeysospathisdirsortedlistdirendswith fw_configZcheck_config_dictZexport_config_dictrcodemsg ExceptionisfileZFIREWALLD_DIRECTr read check_configZ export_configZLOCKDOWN_WHITELISTr ZFIREWALLD_CONFr ) fwrZreadersrZ_dirfileobjerrorrr&/usr/lib/python3.6/functions.pyr!&sz   &. ($ ($  (r!)rZfirewallrZfirewall.errorsrZfirewall.core.fw_configrZfirewall.core.io.zonerZfirewall.core.io.servicerZfirewall.core.io.ipsetrZfirewall.core.io.icmptyperZfirewall.core.io.helperr Zfirewall.core.io.policyr Zfirewall.core.io.directr Z#firewall.core.io.lockdown_whitelistr Zfirewall.core.io.firewalld_confr r!r&r&r&r's            PKpge[)`/`/-io/__pycache__/io_object.cpython-36.opt-1.pycnu[3 g5@sdZddddddddgZd d ljZd d ljjZd d lZd d lZd d lm Z d d l m Z d d l m Z d dl mZd dlmZejdkZGdddeZGdddeZGdddeZGdddeZGdddejjZGdddejZddZddZddZ ddZ!d S)z5Generic io_object handler, io specific check methods.PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol check_addressN) OrderedDict) functions)b2u)errors) FirewallError3c@s|eZdZdZfZdZgZiZiZddZ ddZ ddZ d d Z d d Z d dZddZddZddZddZddZdS)rz; Abstract IO_Object as base for icmptype, service and zone z()cCs"d|_d|_d|_d|_d|_dS)NF)filenamepathnamedefaultZbuiltin)selfr/usr/lib/python3.6/io_object.py__init__2s zIO_Object.__init__cCs6g}x(|jD]}|jtjt||dq Wt|S)Nr )IMPORT_EXPORT_STRUCTUREappendcopydeepcopygetattrtuple)rretxrrr export_config9s zIO_Object.export_configcCsXi}tdd|jD}x:|D]2}t||sAsz0IO_Object.export_config_dict..)dictrr isinstanceboolrr)rconf type_formatskeyrrrexport_config_dict?s  zIO_Object.export_config_dictcCs|j|xt|jD]~\}\}}t||tr~g}t}x,||D] }||krD|j||j|qDW~t||t j |qt||t j ||qWdS)N) check_config enumeraterr&listsetraddsetattrrr)rr(ielementZdummyZ_confZ_setr rrr import_configGs  zIO_Object.import_configc Cs~|j|xn|D]f}t||s0ttjdj|t||tr`t||tt j t j ||qt||t j ||qWdS)Nz-Internal error. '{}' is not a valid attribute) check_config_dicthasattrrr Z UNKNOWN_ERRORformatr&r.r1r fromkeysrr)rr(r*rrrimport_config_dictWs   "zIO_Object.import_config_dictcCszt|ts(ttjd|tdt|ft|dkr@ttjdx4|D],}|j rF||j krFttjd||fqFWdS)Nz'%s' not of type %s, but %srr"zname can't be emptyz'%s' is not allowed in '%s') r&strrr INVALID_TYPEtypelenZ INVALID_NAMEisalnumADDITIONAL_ALNUM_CHARS)rrcharrrr check_namecs     zIO_Object.check_namecCsjt|t|jkr0ttjdt|t|jfi}x&t|jD]\}\}}||||<q@W|j|dS)Nz structure size mismatch %d != %d)r=rrr r;r-r5)rr(Z conf_dictr2r yrrrr,pszIO_Object.check_configcCsrtdd|jD}xX|D]P}|dd|jDkrDttjdj||j|||||j||||qWdS)NcSsg|]}|d|dfqS)r r"r)r#r rrrr$|sz/IO_Object.check_config_dict..cSsg|] \}}|qSrr)r#r rBrrrr$~szoption '{}' is not valid)r%rrr ZINVALID_OPTIONr7_check_config_structure _check_config)rr(r)r*rrrr5{s  zIO_Object.check_config_dictcCsdS)Nr)rZdummy1Zdummy2Zdummy3rrrrDszIO_Object._check_configc Cs`t|t|s,ttjd|t|t|ft|trrt|dkrRttjd|x|D]}|j||dqXWnt|trt|t|krttjd|t|fxt |D]\}}|j|||qWnt|t r\t|j d\}}xn|j D]b\}}t|t|s,ttjd|t|t|ft|t|sttjd|t|t|fqWdS)Nz'%s' not of type %s, but %sr"zlen('%s') != 1r zlen('%s') != %d) r&r<rr r;r.r=rCrr-r%items) rr(Z structurer r2valueZskeyZsvaluer*rrrrCs8      z!IO_Object._check_config_structurecCs|j}d}||jkrdd}|j|dk rdx:|j|D],}||krL|j|q4ttjd||fq4W||jkrd}x$|j|D]}||kr~|j|q~W|sttjd|x |D]}ttjd||fqWdS)NFTzMissing attribute %s for %szUnexpected element %sz%s: Unexpected attribute %s)ZgetNamesPARSER_REQUIRED_ELEMENT_ATTRSremoverr Z PARSE_ERRORPARSER_OPTIONAL_ELEMENT_ATTRS)rrattrsZ_attrsfoundr rrrparser_check_element_attrss,     z$IO_Object.parser_check_element_attrsN)__name__ __module__ __qualname____doc__rZDBUS_SIGNATUREr?rGrIrr!r+r4r9rAr,r5rDrCrLrrrrr)s"   !cs$eZdZfddZddZZS)UnexpectedElementErrorcstt|j||_dS)N)superrQrr)rr) __class__rrrszUnexpectedElementError.__init__cCs d|jS)NzUnexpected element '%s')r)rrrr__str__szUnexpectedElementError.__str__)rMrNrOrrT __classcell__rr)rSrrQs rQcs$eZdZfddZddZZS)MissingAttributeErrorcstt|j||_||_dS)N)rRrVrr attribute)rrrW)rSrrrszMissingAttributeError.__init__cCsd|j|jfS)Nz$Element '%s': missing '%s' attribute)rrW)rrrrrTszMissingAttributeError.__str__)rMrNrOrrTrUrr)rSrrVs rVcs$eZdZfddZddZZS)UnexpectedAttributeErrorcstt|j||_||_dS)N)rRrXrrrW)rrrW)rSrrrsz!UnexpectedAttributeError.__init__cCsd|j|jfS)Nz'Element '%s': unexpected attribute '%s')rrW)rrrrrTsz UnexpectedAttributeError.__str__)rMrNrOrrTrUrr)rSrrXs rXc@s4eZdZddZddZddZddZd d Zd S) rcCs||_d|_dS)Nr)item_element)rrYrrrrsz!IO_Object_ContentHandler.__init__cCs d|_dS)Nr)rZ)rrrr startDocumentsz&IO_Object_ContentHandler.startDocumentcCs d|_dS)Nr)rZ)rrrJrrr startElementsz%IO_Object_ContentHandler.startElementcCs*|dkr|j|j_n|dkr&|j|j_dS)Nshort description)rZrYr]r^)rrrrr endElements z#IO_Object_ContentHandler.endElementcCs|j|jdd7_dS)N  )rZreplace)rcontentrrr characterssz#IO_Object_ContentHandler.charactersN)rMrNrOrr[r\r_rdrrrrrs c@s<eZdZddZddZddZddZd d Zd d Zd S)rcCsNtjjj||j|_|j|_ig|_|jd|_ g|_ d|_ d|_ d|_ dS)Nr"zutf-8F)saxhandlerContentHandlerrwrite_writeflushZ_flushZ _ns_contextsZ_current_contextZ_undeclared_ns_mapsZ _encodingZ_pending_start_elementZ_short_empty_elements)routrrrrs zIO_Object_XMLGenerator.__init__cCs*trdd|jD}tjj|||dS)a saxutils.XMLGenerator.startElement() expects name and attrs to be unicode and bad things happen if any of them is (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. cSsi|]\}}t|t|qSr)r )r#rrFrrr sz7IO_Object_XMLGenerator.startElement..N)rrEsaxutils XMLGeneratorr\)rrrJrrrr\sz#IO_Object_XMLGenerator.startElementcCstrX|jdt|x4|jD](\}}|jdt|tjt|fq W|jdnF|jd|x,|jD] \}}|jd|tj|fqpW|jddS)z* slightly modified startElement() N)rrjr rErnZ quoteattr)rrrJrFrrr simpleElements  z$IO_Object_XMLGenerator.simpleElementcCstjj|t|dS)z saxutils.XMLGenerator.endElement() expects name to be unicode and bad things happen if it's (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. N)rnror_r )rrrrrr_sz!IO_Object_XMLGenerator.endElementcCstjj|t|dS)z saxutils.XMLGenerator.characters() expects content to be unicode and bad things happen if it's (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. N)rnrordr )rrcrrrrd%sz!IO_Object_XMLGenerator.characterscCstjj|t|dS)a saxutils.XMLGenerator.ignorableWhitespace() expects content to be unicode and bad things happen if it's (utf-8) encoded. We override the method here to sanitize this case. Can be removed once we drop Python2 support. N)rnroignorableWhitespacer )rrcrrrrr-sz*IO_Object_XMLGenerator.ignorableWhitespaceN) rMrNrOrr\rqr_rdrrrrrrrs  cCstj|}|dkr$ttjd|n`|dkr>ttjd|nF|dkrXttjd|n,t|dkr|d|dkrttjd|dS) Nzport number in '%s' is too bigr"z'%s' is invalid port rangezport range '%s' is ambiguousr re)r Z getPortRangerr Z INVALID_PORTr=)ZportZ port_rangerrrr5s    cCs|dkrttjd|dS)Ntcpudpsctpdccpz)'%s' not from {'tcp'|'udp'|'sctp'|'dccp'})rurvrwrx)rr INVALID_PROTOCOL)protocolrrrrDscCstj|sttj|dS)N)r Z checkProtocolrr ry)rzrrrrJs cCs$tj||s ttjd||fdS)Nz'%s' is not valid %s address)r rrr Z INVALID_ADDR)ZipvZaddrrrrrNs )"rP__all__Zxml.saxrfZxml.sax.saxutilsrnrsys collectionsr Zfirewallr Zfirewall.functionsr r Zfirewall.errorsrversionrobjectr ExceptionrQrVrXrgrhrrorrrrrrrrrs0           CPKpge[{k",io/__pycache__/icmptype.cpython-36.opt-1.pycnu[3 g@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)IcmpTypeicmptype_readericmptype_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log)errors) FirewallErrorcspeZdZdddddgffZdZddgZd d d d Zd dgd d gdZfddZddZ ddZ ddZ Z S)rversionshort description destinationz(sssas)_-N)rricmptypenameipv4ipv6)rrcs*tt|jd|_d|_d|_g|_dS)Nr)superr__init__rrrr)self) __class__/usr/lib/python3.6/icmptype.pyr8s zIcmpType.__init__cCs"d|_d|_d|_|jdd=dS)Nr)rrrr)rrrrcleanup?szIcmpType.cleanupcCs:t|j|_t|j|_t|j|_dd|jD|_dS)z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSsg|] }t|qSr)r).0mrrr Lsz+IcmpType.encode_strings..N)rrrrr)rrrrencode_stringsEs   zIcmpType.encode_stringscCs2|dkr.x$|D]}|dkrttjd|qWdS)Nrrrz'%s' not from {'ipv4'|'ipv6'})rr)r r ZINVALID_DESTINATION)rritemZ all_configrrrr _check_configNs  zIcmpType._check_config)rr)rr)rr) __name__ __module__ __qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrrr#r% __classcell__rr)rrr%s    c@seZdZddZdS)icmptype_ContentHandlercCstj||||jj|||dkrTd|kr>tjd|dd|kr|d|j_nT|dkr^nJ|dkrhn@|dkrx6d D].}||krv||jd krv|jjj t |qvWdS)Nrrz'Ignoring deprecated attribute name='%s'rrrrrryestrue)rr)r+r,) r startElementr$Zparser_check_element_attrsr Zwarningrlowerrappendstr)rrattrsxrrrr-Ys"  z$icmptype_ContentHandler.startElementN)r&r'r(r-rrrrr*Xsr*c Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz%s is missing .xml suffixFTz%s/%srbznot a valid icmptype file: %s)rendswithr r Z INVALID_NAMErZ check_namefilenamepath startswithr ETC_FIREWALLDZbuiltindefaultr*saxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_ICMPTYPEZ getExceptionrr#) r7r8rhandlerparserrfsourcemsgrrrrms8        (c Cs.|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jd ||jd |jrt|jd krt|jd |jdi|j|j|jd|jd |jr|jd kr|jd |jdi|j|j|jd|jd |jr|jd i}x|jD]} d|| <qW|jd||jd |jd |jd |j|j~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrr z rrr+r)r8r7rosexistsshutilZcopy2 Exceptionr errordirnamer9rr:mkdirior=r Z startDocumentrr-ZignorableWhitespacerZ charactersZ endElementrrZ simpleElementZ endDocumentclose) rr8_pathrrCdirpathrAr?r1r2rrrrs\                       )N)__all__Zxml.saxr<rGrNrIZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr r Zfirewall.core.loggerr r Zfirewall.errorsr rr*rrrrrrs       3PKpge[{k"&io/__pycache__/icmptype.cpython-36.pycnu[3 g@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)IcmpTypeicmptype_readericmptype_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log)errors) FirewallErrorcspeZdZdddddgffZdZddgZd d d d Zd dgd d gdZfddZddZ ddZ ddZ Z S)rversionshort description destinationz(sssas)_-N)rricmptypenameipv4ipv6)rrcs*tt|jd|_d|_d|_g|_dS)Nr)superr__init__rrrr)self) __class__/usr/lib/python3.6/icmptype.pyr8s zIcmpType.__init__cCs"d|_d|_d|_|jdd=dS)Nr)rrrr)rrrrcleanup?szIcmpType.cleanupcCs:t|j|_t|j|_t|j|_dd|jD|_dS)z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSsg|] }t|qSr)r).0mrrr Lsz+IcmpType.encode_strings..N)rrrrr)rrrrencode_stringsEs   zIcmpType.encode_stringscCs2|dkr.x$|D]}|dkrttjd|qWdS)Nrrrz'%s' not from {'ipv4'|'ipv6'})rr)r r ZINVALID_DESTINATION)rritemZ all_configrrrr _check_configNs  zIcmpType._check_config)rr)rr)rr) __name__ __module__ __qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrrr#r% __classcell__rr)rrr%s    c@seZdZddZdS)icmptype_ContentHandlercCstj||||jj|||dkrTd|kr>tjd|dd|kr|d|j_nT|dkr^nJ|dkrhn@|dkrx6d D].}||krv||jd krv|jjj t |qvWdS)Nrrz'Ignoring deprecated attribute name='%s'rrrrrryestrue)rr)r+r,) r startElementr$Zparser_check_element_attrsr Zwarningrlowerrappendstr)rrattrsxrrrr-Ys"  z$icmptype_ContentHandler.startElementN)r&r'r(r-rrrrr*Xsr*c Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz%s is missing .xml suffixFTz%s/%srbznot a valid icmptype file: %s)rendswithr r Z INVALID_NAMErZ check_namefilenamepath startswithr ETC_FIREWALLDZbuiltindefaultr*saxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_ICMPTYPEZ getExceptionrr#) r7r8rhandlerparserrfsourcemsgrrrrms8        (c Cs.|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jd ||jd |jrt|jd krt|jd |jdi|j|j|jd|jd |jr|jd kr|jd |jdi|j|j|jd|jd |jr|jd i}x|jD]} d|| <qW|jd||jd |jd |jd |j|j~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrr z rrr+r)r8r7rosexistsshutilZcopy2 Exceptionr errordirnamer9rr:mkdirior=r Z startDocumentrr-ZignorableWhitespacerZ charactersZ endElementrrZ simpleElementZ endDocumentclose) rr8_pathrrCdirpathrAr?r1r2rrrrs\                       )N)__all__Zxml.saxr<rGrNrIZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr r Zfirewall.core.loggerr r Zfirewall.errorsr rr*rrrrrrs       3PKpge[>)io/__pycache__/ifcfg.cpython-36.opt-1.pycnu[3 g@s^dZdgZddlZddlZddlZddlZddlmZddl m Z m Z m Z Gddde ZdS)zifcfg file parserifcfgN)log)b2uu2bPY2c@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)rcCsi|_g|_||_|jdS)N)_config_deletedfilenameclear)selfr r /usr/lib/python3.6/ifcfg.py__init__#szifcfg.__init__cCsi|_g|_dS)N)rr)r r r r r )sz ifcfg.clearcCs|jjdS)N)rr )r r r r cleanup-sz ifcfg.cleanupcCs|jj|jS)N)rgetstrip)r keyr r r r0sz ifcfg.getcCs8t|j}t|j|j|<||jkr4|jj|dS)N)rrrrremove)r rvalueZ_keyr r r set3s  z ifcfg.setcCsHd}x2|jjD]$\}}|r$|d7}|d||f7}qWtrDt|S|S)N z%s=%s)ritemsrr)r srrr r r __str__9s z ifcfg.__str__cCsB|jyt|jd}Wn4tk rL}ztjd|j|WYdd}~XnXx|D]}|s^P|j}t|dksT|ddkrqTdd|jd dD}t|d krqTt|dd kr|dj d r|dj d r|ddd|d<|dd krqTn,|j j |ddk r tj d |j|jqT|d|j |d<qTW|jdS)NrzFailed to load '%s': %sr#;cSsg|] }|jqSr )r).0xr r r Qszifcfg.read..="rz%%s: Duplicate option definition: '%s')rr)r openr Exceptionrerrorrlensplit startswithendswithrrZwarningclose)r fmsglineZpairr r r readBs2   z ifcfg.readc :Cst|jdkrdSg}y.tjddtjj|jtjj|jdd}Wn2t k rv}zt j d|WYdd}~XnXd}d}yt j |jddd }WnNt k r}z0tjj|jrt j d |j|fnd}WYdd}~XndXx^|D]T}|sP|jd }t|dkr(|sD|jd d }q|d dkrPd}|j||jd q|jdd}t|dkr~d}|j|d q|d j} |dj} t| dkr| jdr| jdr| dd} | |kr@| |jkr|j| | krd}|jd| |j| fd }n$| |jkr"d }nd}|j|d |j| qd }qWt|jd krxF|jjD]8\} } | |krzqd|sd }|jd| | fd }qdW|r|j|j|stj|jdStjj|jr8ytj|jd|jWnBt k r6}z$tj|jtd|j|fWYdd}~XnXytj|j|jWnBt k r}z$tj|jtd|j|fWYdd}~XnXtj|jddS)NrZwtz%s.F)modeprefixdirdeletez!Failed to open temporary file: %sZrtzUTF-8)r2encodingzFailed to open '%s': %srTrrr"r#r$z%s=%s z%s.bakzBackup of '%s' failed: %szFailed to create '%s': %sir%)r)rtempfileZNamedTemporaryFileospathbasenamer dirnamer'rr(ior&existsrwriter*r+r,rappendrr-rnameshutilZcopy2IOErrorZmovechmod) r doneZ temp_filer/Zmodifiedemptyr.r0prrr r r r>_s               $ $z ifcfg.writeN) __name__ __module__ __qualname__rr rrrrr1r>r r r r r"s )__doc____all__Zos.pathr8r<r7rAZfirewall.core.loggerrZfirewall.functionsrrrobjectrr r r r s PKpge[I}h%h%6io/__pycache__/lockdown_whitelist.cpython-36.opt-1.pycnu[3 g1@sddljZddlZddlZddlZddlmZddlmZm Z m Z m Z ddl m Z ddlmZmZmZmZmZmZddlmZddlmZGdd d e ZGd d d e ZdS) N)config)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log)uniqify checkUsercheckUid checkCommand checkContext u2b_if_py2)errors) FirewallErrorc@seZdZddZddZdS)!lockdown_whitelist_ContentHandlercCstj||d|_dS)NF)r__init__ whitelist)selfitemr(/usr/lib/python3.6/lockdown_whitelist.pyr%s z*lockdown_whitelist_ContentHandler.__init__c CsVtj||||jj|||dkr@|jr6ttjdd|_n|dkrr|js\tj ddS|d}|jj |n|dkr|jstj ddSd |kryt |d }Wn&t k rtj d |d dSX|jj |nd|kr|jj|dn\|d kr@|jstj d dSd |kr.tj ddS|jj|d ntj d|dSdS)NrzMore than one whitelist.Tcommandz)Parse Error: command outside of whitelistnameuserz&Parse Error: user outside of whitelistidz"Parse Error: %s is not a valid uidselinuxz)Parse Error: selinux outside of whitelistcontextzParse Error: no contextzUnknown XML element %s)r startElementrZparser_check_element_attrsrrrZ PARSE_ERRORrerror add_commandint ValueErroradd_uidadd_user add_context)rrZattrsruidrrrr)sJ        z.lockdown_whitelist_ContentHandler.startElementN)__name__ __module__ __qualname__rrrrrrr$srcs4eZdZdZddgfddgfddgfddgffZdZd gZd d gd d gd Zddd giZfddZ ddZ ddZ ddZ ddZ ddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z d@dAZ!dBdCZ"Z#S)DLockdownWhitelistz LockdownWhitelist class commandscontextsusersuidsrz (asasasai)_Nrr)rrrrrrcs6tt|j||_d|_g|_g|_g|_g|_dS)N) superr)rfilenameparserr*r,r-r.)rr1) __class__rrrnszLockdownWhitelist.__init__cCs|d kr.x|D]}|j||dd |qWnv|dkrLt|sttj|nX|dkrjt|sttj|n:|dkrt|sttj|n|d krt |sttj |dS) Nr*r,r-r.rrrr%)r*r,r-r.) _check_configr rrINVALID_COMMANDr INVALID_CONTEXTr INVALID_USERr INVALID_UID)rrrZ all_configxrrrr6ys zLockdownWhitelist._check_configcCs4|jdd=|jdd=|jdd=|jdd=dS)N)r*r,r-r.)rrrrcleanups   zLockdownWhitelist.cleanupcCs:dd|jD|_dd|jD|_dd|jD|_dS)z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSsg|] }t|qSr)r ).0r;rrr sz4LockdownWhitelist.encode_strings..cSsg|] }t|qSr)r )r=r;rrrr>scSsg|] }t|qSr)r )r=r;rrrr>sN)r*r,r-)rrrrencode_stringssz LockdownWhitelist.encode_stringscCs@t|sttj|||jkr,|jj|nttjd|dS)Nz!Command "%s" already in whitelist)r rrr7r*appendALREADY_ENABLED)rrrrrrs   zLockdownWhitelist.add_commandcCs,||jkr|jj|nttjd|dS)NzCommand "%s" not in whitelist.)r*removerr NOT_ENABLED)rrrrrremove_commands z LockdownWhitelist.remove_commandcCs ||jkS)N)r*)rrrrr has_commandszLockdownWhitelist.has_commandcCsBx<|jD]2}|jdr.|j|ddr:dSq||krdSqWdS)N*r4TFr5)r*endswith startswith)rrZ_commandrrr match_commands  zLockdownWhitelist.match_commandcCs|jS)N)r*)rrrr get_commandsszLockdownWhitelist.get_commandscCsDt|sttjt|||jkr0|jj|nttjd|dS)NzUid "%s" already in whitelist)r rrr:strr.r@rA)rr%rrrr"s  zLockdownWhitelist.add_uidcCs,||jkr|jj|nttjd|dS)NzUid "%s" not in whitelist.)r.rBrrrC)rr%rrr remove_uids zLockdownWhitelist.remove_uidcCs ||jkS)N)r.)rr%rrrhas_uidszLockdownWhitelist.has_uidcCs ||jkS)N)r.)rr%rrr match_uidszLockdownWhitelist.match_uidcCs|jS)N)r.)rrrrget_uidsszLockdownWhitelist.get_uidscCs@t|sttj|||jkr,|jj|nttjd|dS)NzUser "%s" already in whitelist)r rrr9r-r@rA)rrrrrr#s   zLockdownWhitelist.add_usercCs,||jkr|jj|nttjd|dS)NzUser "%s" not in whitelist.)r-rBrrrC)rrrrr remove_users zLockdownWhitelist.remove_usercCs ||jkS)N)r-)rrrrrhas_userszLockdownWhitelist.has_usercCs ||jkS)N)r-)rrrrr match_userszLockdownWhitelist.match_usercCs|jS)N)r-)rrrr get_usersszLockdownWhitelist.get_userscCs@t|sttj|||jkr,|jj|nttjd|dS)Nz!Context "%s" already in whitelist)r rrr8r,r@rA)rrrrrr$"s   zLockdownWhitelist.add_contextcCs,||jkr|jj|nttjd|dS)NzContext "%s" not in whitelist.)r,rBrrrC)rrrrrremove_context,s z LockdownWhitelist.remove_contextcCs ||jkS)N)r,)rrrrr has_context3szLockdownWhitelist.has_contextcCs ||jkS)N)r,)rrrrr match_context6szLockdownWhitelist.match_contextcCs|jS)N)r,)rrrr get_contexts9szLockdownWhitelist.get_contextscCs|j|jjds&ttjd|jt|}tj}|j |y|j |jWn8tj k r}zttj d|j WYdd}~XnX~~tr|jdS)Nz.xmlz'%s' is missing .xml suffixzNot a valid file: %s)r<r1rGrrZ INVALID_NAMErsaxZ make_parserZsetContentHandlerparseZSAXParseExceptionZ INVALID_TYPEZ getExceptionrr?)rhandlerr2msgrrrread>s"   zLockdownWhitelist.readcCstjj|jr\ytj|jd|jWn4tk rZ}ztd|j|fWYdd}~XnXtjjtj sxtj tj dt j |jddd}t |}|j|jdi|jdx6t|jD](}|jd |jd d |i|jdqWx:t|jD],}|jd |jd d t|i|jdqWx8t|jD]*}|jd |jd d |i|jdq0Wx8t|jD]*}|jd |jdd|i|jdqjW|jd|jd|j|j~dS)Nz%s.oldzBackup of '%s' failed: %siZwtzUTF-8)modeencodingr z rrrrrr)ospathexistsr1shutilZcopy2 ExceptionIOErrorrZ ETC_FIREWALLDmkdirioopenrZ startDocumentrZignorableWhitespacerr*Z simpleElementr.rKr-r,Z endElementZ endDocumentclose)rr[frZrr%rrrrrwriteQsB$         zLockdownWhitelist.write)$r&r'r(__doc__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr6r<r?rrDrErIrJr"rLrMrNrOr#rPrQrRrSr$rTrUrVrWr\rk __classcell__rr)r3rr)WsL         1 r))Zxml.saxrXr`rgrcZfirewallrZfirewall.core.io.io_objectrrrrZfirewall.core.loggerrZfirewall.functionsrr r r r r rZfirewall.errorsrrr)rrrrs      3PKpge[E-22"io/__pycache__/zone.cpython-36.pycnu[3 gM@sdddgZddljZddlZddlZddlZddlmZddlm Z m Z m Z m Z m Z mZmZddlmZmZddlmZmZmZmZdd lmZmZmZmZdd lmZdd lm Z dd lm!Z!dd l"m#Z#GdddeZ$GdddeZ%dddZ&dddZ'dS)Zone zone_reader zone_writerN)config) checkIPnMask checkIP6nMaskcheckInterfaceuniqifymax_zone_name_len u2b_if_py2 check_mac)DEFAULT_ZONE_TARGET ZONE_TARGETS)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)common_startElementcommon_endElementcommon_check_config common_writer)rich)log)errors) FirewallErrorcsfeZdZdZd@dAdBdCdDd dgfd dEgfd dgfdFd dGgfddgfddgfddgfddgfddHgfdIdJfZdddgZddddgddgdgdgdddgdgddddgddgddddddgdgddZddddgd gd!d"gd#d$gd%d&d'd#d(gd%d'd(gd)d*gd+gd,gd- Zed.d/Z fd0d1Z d2d3Z d4d5Z fd6d7Z fd8d9Zd:d;Zfdd?ZZS)Krz Zone class versionshort descriptionUNUSEDFtargetservicesports icmp_blocks masquerade forward_ports interfacessources rules_str protocols source_portsicmp_block_inversionforward_-/Nnameportprotocolvalueset)rrzoneservicer1z icmp-blockz icmp-typer,z forward-port interfacerulesource destinationr2z source-portrZauditZacceptrejectZdropZmarklimitzicmp-block-inversion immutableZenabledzto-portzto-addrfamilyZpriorityaddressmacinvertipsetprefixleveltypeZburst) r5r$z forward-portr8r9r:rr;r<cCs8x&ttjD]\}\}}||kr |Sq WttjddS)Nz index_of()) enumeraterIMPORT_EXPORT_STRUCTURErrZ UNKNOWN_ERROR)elementiZelZdummyrJ/usr/lib/python3.6/zone.pyindex_ofdsz Zone.index_ofcstt|jd|_d|_d|_d|_t|_g|_ g|_ g|_ g|_ d|_ d|_g|_g|_g|_g|_d|_g|_g|_d|_d|_d|_dS)NrF)superr__init__rrrrr r r!r"r)r#r,r$r%r*r&r' fw_configrulesr(r+combinedapplied)self) __class__rJrKrNks,z Zone.__init__cCsd|_d|_d|_d|_t|_|jdd=|jdd=|jdd=|j dd=d|_ d|_ |j dd=|j dd=|jdd=|jdd=d|_|jdd=|jdd=d|_d|_d|_dS)NrF)rrrrr r r!r"r)r#r,r$r%r*r&r'rOrPr(r+rQrR)rSrJrJrKcleanups*          z Zone.cleanupcCst|j|_t|j|_t|j|_t|j|_dd|jD|_dd|jD|_dd|jD|_dd|jD|_dd|j D|_ dd|j D|_ dd|j D|_ d d|j D|_ d d|j D|_ d d|jD|_d S) z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSsg|] }t|qSrJ)r ).0srJrJrK sz'Zone.encode_strings..cSs g|]\}}t|t|fqSrJ)r )rVpoprrJrJrKrXscSsg|] }t|qSrJ)r )rVrZrJrJrKrXscSsg|] }t|qSrJ)r )rVrIrJrJrKrXscSs0g|](\}}}}t|t|t|t|fqSrJ)r )rVZp1Zp2Zp3Zp4rJrJrKrXscSs g|]\}}t|t|fqSrJ)r )rVrYrZrJrJrKrXscSsg|] }t|qSrJ)r )rVrIrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXsN)r rrrr r!r"r)r#r%r*r&r'rPr()rSrJrJrKencode_stringss     zZone.encode_stringscsN|dkr8dd|D|_tt|j|dd|jDntt|j||dS)Nr(cSsg|]}tj|dqS))Zrule_str)rZ Rich_Rule)rVrWrJrJrKrXsz$Zone.__setattr__..cSsg|] }t|qSrJ)str)rVrWrJrJrKrXs)rPrMr __setattr__)rSr0r3)rTrJrKr]s zZone.__setattr__cstt|j}|d=|S)Nr)rMrexport_config_dict)rSZconf)rTrJrKr^szZone.export_config_dictcCsLt|||||dkr.|tkr*ttj|n|dkrxl|D]d}t|sTttj||jr}||j krq||jj |jkrttjdj ||qWqWdS)Nr r&z)interface '{}' already bound to zone '{}'r'zipset:z&source '{}' already bound to zone '{}')rrrrINVALID_TARGETrZINVALID_INTERFACErOZ get_zonesr0Zget_zoner&formatrrr startswith INVALID_ADDRr')rSritemZ all_configr7r5r9rJrJrK _check_configs6       zZone._check_configcstt|j||jdr,ttjd|n|jdrHttjd|n|jddkrhttjd|nnd|kr|d|j d}n|}t |t krttjd|t |t |j f|j r||j jkrttjddS)Nr/z'%s' can't start with '/'z'%s' can't end with '/'zmore than one '/' in '%s'z'Zone of '%s' has %d chars, max is %d %sz+Zones can't have the same name as a policy.)rMr check_namerarr INVALID_NAMEendswithcountfindlenr rQrOZget_policy_objectsZ NAME_CONFLICT)rSr0Z checked_name)rTrJrKrfs,      zZone.check_namec Csd|_d|_d|_d|_d|_x$|jD]}||jkr&|jj|q&Wx$|jD]}||jkrL|jj|qLWx$|jD]}||jkrr|jj|qrWx$|j D]}||j kr|j j|qWx$|j D]}||j kr|j j|qWx$|j D]}||j kr|j j|qW|j rd|_ |j rd|_ x(|jD]}||jkr&|jj|q&Wx(|jD]}||jkrP|jj|qPWx,|jD]"} |jj| |jjt| qzW|jrd|_dS)NTr)rQfilenamerrrr&appendr'r!r"r)r#r,r$r%r*rPr(r\r+) rSr5r7r9r6r1protoZicmpr,r8rJrJrKcombinesL                  z Zone.combine)rr)rr)rr)rF)r r)rr)r$F)rrrr)rr)r+F)r,F)__name__ __module__ __qualname____doc__rGZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRS staticmethodrLrNrUr[r]r^rdrfro __classcell__rJrJ)rTrKr(sx         c@s$eZdZddZddZddZdS)zone_ContentHandlercCs"tj||d|_d|_d|_dS)NF)rrN_rule _rule_errorZ _limit_ok)rSrcrJrJrKrN s zzone_ContentHandler.__init__c Cstj||||jrdS|jj||t|||r6dS|dkrd|krVtjd|dd|krj|d|j_d|krtjd|dd|kr|d}|t krt t j ||dkr|t kr||j_n|d kr|jjrtjd nd |j_n|d krh|jrtjd d |_dSd|kr.tjdd |_dS|d|jjkrT|jjj|dntjd|dn8|dkrf|jr |jjrtjdt|jd |_dSd}d|kr|djd$krd }d}}}d|kr|d}d|kr|d}d|kr|d}tj||||d|j_dSd|krBd|krBtjddSd|krdd|krdtjddSd|kr~tjd|dd|krtjddSd|krt|d rt|d rt|d rt t j|dd|kr$d|d}||jjkr|jjj|ntjd |dd|kr|d}||jjkrT|jjj|ntjd |dn:|d!kr|jjrtjd"nd |j_ntjd#|dSdS)%Nr5r0z'Ignoring deprecated attribute name='%s'rr=z,Ignoring deprecated attribute immutable='%s'r rr,zForward already set, ignoring.Tr7z$Invalid rule: interface use in rule.z Invalid interface: Name missing.z%Interface '%s' already set, ignoring.r9z:Invalid rule: More than one source in rule '%s', ignoring.FrAyestruer?r@rB)rAz$Invalid source: No address no ipset.z"Invalid source: Address and ipset.r>z)Ignoring deprecated attribute family='%s'z+Invalid source: Invertion not allowed here.zipset:%sz"Source '%s' already set, ignoring.zicmp-block-inversionz+Icmp-Block-Inversion already set, ignoring.zUnknown XML element '%s')ryrz)r startElementrxrcZparser_check_element_attrsrrZwarningrrrrr_r r r,rwr&rmr9r\lowerrZ Rich_Sourcerrr rbr'r+) rSr0attrsr rAZaddrr@rBentryrJrJrKr{&s                                       z zone_ContentHandler.startElementcCstj||t||dS)N)r endElementr)rSr0rJrJrKrs zzone_ContentHandler.endElementN)rprqrrrNr{rrJrJrJrKrvsprvFc Cst}|jds ttjd||dd |_|s>|j|j||_||_|j t j rZdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r} zttjd| jWYdd} ~ XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid zone file: %s)rrhrrrgr0rfrlpathrar ETC_FIREWALLDZbuiltindefaultrvsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZ INVALID_ZONEZ getExceptionrr[) rlrZ no_check_namer5handlerparserr0fr9msgrJrJrKrs:        (c Cs\|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jtkr*|j|d <|jd ||jd t||x8t|jD]*} |jd|jdd| i|jd qVWx\t|jD]N} |jdd| kr|jdd| ddin|jdd| i|jd qW|jr |jd|jdi|jd |jr2|jd|jdi|jd |jd |jd |j |j!~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrr r5 z r7r0zipset:r9rBr?zicmp-block-inversionr,)"rrlr0osexistsshutilZcopy2 ExceptionrerrordirnamerarrmkdiriorrZ startDocumentrr r r{ZignorableWhitespacerr r&Z simpleElementr'r+r,rZ endDocumentclose) r5r_pathr0rdirpathrrr}r7r9rJrJrKrs`                     )F)N)(__all__Zxml.saxrrrrZfirewallrZfirewall.functionsrrrr r r r Zfirewall.core.baser rZfirewall.core.io.io_objectrrrrZfirewall.core.io.policyrrrrZ firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrrvrrrJrJrJrKs$   $    x| PKpge[V..$io/__pycache__/direct.cpython-36.pycnu[3 g=@sddljZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddl mZmZmZddlmZddlmZddlmZdd lmZdd lmZGd d d eZGd ddeZdS)N)config)LastUpdatedOrderedDict) splitArgsjoinArgs u2b_if_py2) IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log) ipXtables)ebtables)errors) FirewallErrorc@s$eZdZddZddZddZdS)direct_ContentHandlercCstj||d|_dS)NF)r__init__direct)selfitemr/usr/lib/python3.6/direct.pyr(s zdirect_ContentHandler.__init__c Cstj||||jj|||dkr@|jr6ttjdd|_n>|dkr|js\tj ddS|d}|d}|d}|jj t |t |t |n|dkr6|jstj d dS|d}|dkrttj d ||d}|d}yt |d}Wn(tk rtj d|ddSXt |t |t ||g|_nH|dkrl|jsVtj ddS|d}t |g|_ntj d|dSdS)NrzMore than one direct tag.Tchainz$Parse Error: chain outside of directipvtablerulez#Parse Error: rule outside of directipv4ipv6ebz"'%s' not from {'ipv4'|'ipv6'|'eb'}priorityz'Parse Error: %s is not a valid priority passthroughz&Parse Error: command outside of directzUnknown XML element %s)rrr)r startElementrZparser_check_element_attrsrrr Z PARSE_ERRORr error add_chainr INVALID_IPVint ValueError_rule _passthrough)rnameZattrsrrrrrrrr,sT          z"direct_ContentHandler.startElementcCstj|||dkrX|jrF|jjddt|jD|jj|jn tj dd|_nJ|dkr|jr|j jddt|jD|jj |j n tj d d|_ dS) NrcSsg|] }t|qSr)r).0xrrr dsz4direct_ContentHandler.endElement..z2Error: rule does not have any arguments, ignoring.rcSsg|] }t|qSr)r)r(r)rrrr*msz0Error: passthrough does not have any arguments, z ignoring.z9Error: passthrough does not have any arguments, ignoring.) r endElementZ_elementr%appendrradd_ruler r r&add_passthrough)rr'rrrr+^s     z direct_ContentHandler.endElementN)__name__ __module__ __qualname__rrr+rrrrr's2rcs<eZdZdZddBgfddddddgfgfdddgfgffZdZdd d d gd d d d gd gd ZiZfddZddZ ddZ ddZ ddZ ddZ ddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z d@dAZ!Z"S)CDirectz Direct class chainsrulesr passthroughsz(a(sss)a(sssias)a(sas))Nrrrr)rrrrcs0tt|j||_t|_t|_t|_dS)N)superr2rfilenamerr3r5r6)rr8) __class__rrrs zDirect.__init__cCsdS)Nr)rconfrZall_confrrr _check_configszDirect._check_configc Csg}g}x>|jD]4}x.|j|D] }|jtt|t|gq WqW|j|g}xR|jD]H}xB|j|D]4}|jt|d|d|d|dt|dfqnWq^W|j|g}x8|jD].}x(|j|D]}|jt|t|fqWqW|j|t|S)Nr)r3r,tuplelistr5r6)rretr)keyrrrrr export_configs$ $     zDirect.export_configcCs|j|j|xt|jD]x\}\}}|dkrNx||D]}|j|qr rRrL)rrrrrrMrAvaluerrrr-s     zDirect.add_rulecCs|j|||||f}|t|f}||jkrb||j|krb|j||=t|j|dkr|j|=n$tddj|||fd||fdS)Nrz(Rule '%s' for table '%s' and chain '%s' z',z)with ipv '%s' and priority %d not in list)rQr>r5rTr$rL)rrrrrrMrArYrrr remove_rules     zDirect.remove_rulecCsb|j|||||f}||jkr^x"|j|jD]}|j||=q0Wt|j|dkr^|j|=dS)Nr)rQr5rPrT)rrrrrArYrrr remove_rules"s   zDirect.remove_rulescCs:|j|||||f}|t|f}||jko8||j|kS)N)rQr>r5)rrrrrrMrArYrrr query_rule+s   zDirect.query_rulecCsF|j|||||f}||jkr*|j|Std||fd|dS)Nz'No rules for table '%s' and chain '%s' z with ipv '%s')rQr5r$)rrrrrArrr get_rules1s     zDirect.get_rulescCs|jS)N)r5)rrrr get_all_rules:szDirect.get_all_rulescCs^|j|||jkrg|j|<||j|kr>|j|j|ntjddj||fddS)NzPassthrough '%s' for ipv '%s'z',zalready in list, ignoring)rOr6r,r rRrL)rrrMrrrr.?s   zDirect.add_passthroughcCsl|j|||jkrN||j|krN|j|j|t|j|dkrh|j|=ntddj||fddS)NrzPassthrough '%s' for ipv '%s'z',z not in list)rOr6rSrTr$rL)rrrMrrrremove_passthroughIs  zDirect.remove_passthroughcCs"|j|||jko ||j|kS)N)rOr6)rrrMrrrquery_passthroughSs zDirect.query_passthroughcCs.|j|||jkr|j|Std|dS)NzNo passthroughs for ipv '%s')rOr6r$)rrrrrget_passthroughsWs   zDirect.get_passthroughscCs|jS)N)r6)rrrrget_all_passthroughs^szDirect.get_all_passthroughscCs|j|jjds&ttjd|jt|}tj}|j |t |jdb}tj d}|j |y|j |Wn8tjk r}zttjd|jWYdd}~XnXWdQRXdS)Nz.xmlz'%s' is missing .xml suffixrbzNot a valid file: %s)rCr8endswithrr Z INVALID_NAMErsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZ INVALID_TYPEZ getException)rhandlerparserfsourcemsgrrrreadcs      z Direct.readc CsBtjj|jr\ytj|jd|jWn4tk rZ}ztd|j|fWYdd}~XnXtjjtj sxtj tj dt j |jddd}t |}|j|jdi|jdxR|jD]H}|\}}x:|j|D],}|jd |jd |||d |jdqWqWx|jD]}|\}}}xx|j|D]j\}} t| d kr@q&|jd |jd |||d|d|jtjjt| |jd |jdq&Wq Wx||jD]r}xj|j|D]\} t| d krȐq|jd |jdd|i|jtjjt| |jd|jdqWqW|jd|jd|j|j~dS)Nz%s.oldzBackup of '%s' failed: %siZwtzUTF-8)modeencodingr z r)rrrr<rz%d)rrrrrr)ospathexistsr8shutilZcopy2 ExceptionIOErrorrZ ETC_FIREWALLDmkdiriorfr Z startDocumentrZignorableWhitespacer3Z simpleElementr5rTreZsaxutilsescaperr+r6Z endDocumentclose) rrlrjrhrArrrrrMrrrwriteusZ$                z Direct.write)r4r4r4)#r/r0r1__doc__rEZDBUS_SIGNATUREZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr;rBrHrCrNrOrQr!rUrVrWrXr-rZr[r\r]r^r.r_r`rarbrmr{ __classcell__rr)r9rr2usH            r2)Zxml.saxrerqrxrtZfirewallrZfirewall.fw_typesrZfirewall.functionsrrrZfirewall.core.io.io_objectrrr Zfirewall.core.loggerr Z firewall.corer r r Zfirewall.errorsrrr2rrrrs        NPKpge[L,io/__pycache__/firewalld_conf.cpython-36.pycnu[3 g5 @s~ddlZddlZddlZddlZddlmZddlmZddl m Z m Z m Z ddddd d d d d ddddg Z GdddeZdS)N)config)log)b2uu2bPY2 DefaultZone MinimalMark CleanupOnExitCleanupModulesOnExitLockdown IPv6_rpfilterIndividualCalls LogDeniedAutomaticHelpersFirewallBackendFlushAllOnReload RFC3964_IPv4AllowZoneDriftingc@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)firewalld_confcCsi|_g|_||_|jdS)N)_config_deletedfilenameclear)selfrr$/usr/lib/python3.6/firewalld_conf.py__init__&szfirewalld_conf.__init__cCsi|_g|_dS)N)rr)rrrrr,szfirewalld_conf.clearcCs|jjg|_dS)N)rrr)rrrrcleanup0s zfirewalld_conf.cleanupcCs|jj|jS)N)rgetstrip)rkeyrrrr4szfirewalld_conf.getcCs8t|j}t|j|j|<||jkr4|jj|dS)N)rrrrremove)rr valueZ_keyrrrset7s  zfirewalld_conf.setcCsHd}x2|jjD]$\}}|r$|d7}|d||f7}qWtrDt|S|S)N z%s=%s)ritemsrr)rsr r"rrr__str__=s zfirewalld_conf.__str__cCs|jyt|jd}Wn8tk rR}ztjd|j||jdtj|jdt tj |jdtj rpdnd|jdtj rdnd|jd tj rdnd|jd tjrdnd|jd tjrdnd|jd tj|jd tj|jdtj|jdtjr dnd|jdtjr"dnd|jdtjr:dndWYdd}~XnXx|D]}|shP|j}t|dks\|dd.krq\dd|jdD}t|dkrtjd|jq\nr|dtkrtjd|jq\nN|ddkrtjd|jq\n*|jj|ddk r:tjd|jq\|d|j|d<q\W|j|jdstjdtj|jdt tj|jd}y t|WnPttfk r|dk rtj d |r|ndtj |jdt tj YnX|jd}| s|j!d/krJ|dk r2tj d#|r(|ndtj |jdtj rDdnd|jd}| sj|j!d0kr|dk rtj d$|r|ndtj |jdtj rdnd|jd }| s|j!d1kr|dk rtj d%|r|ndtj |jd tj rdnd|jd }| s"|j!d2kr^|dk rFtj d&|r<|ndtj|jd tjrXdnd|jd }| s~|j!d3kr|dk rtj d'|r|ndtj|jd tjrdnd|jd }| s|tj"kr|dk rtj d(|tj|jd t tj|jd }| s&|j!tj#kr\|dk rJtj d)|r@|ndtj|jd t tj|jd}| s~|j!tj$kr|dk rtj d*|r|ndtj|jdt tj|jd}| s|j!d4kr |dk rtj d+|r|ndtj|jdt tj|jd}| s*|j!d5kr`|dk rNtj d,|rD|ndtj|jdt tj|jd}| s|j!d6kr|dk rtj d-|r|ndtj|jdt tjdS)7NrzFailed to load '%s': %srrr yesnor r r r rrrrrrr#;cSsg|] }|jqSr)r).0xrrr bsz'firewalld_conf.read..=zInvalid option definition: '%s'zInvalid option: '%s'r$zMissing value: '%s'z!Duplicate option definition: '%s'z0DefaultZone is not set, using default value '%s'z7MinimalMark '%s' is not valid, using default value '%d'falsetruez7CleanupOnExit '%s' is not valid, using default value %sz>CleanupModulesOnExit '%s' is not valid, using default value %sz2Lockdown '%s' is not valid, using default value %sz7IPv6_rpfilter '%s' is not valid, using default value %sz9IndividualCalls '%s' is not valid, using default value %sz3LogDenied '%s' is invalid, using default value '%s'z:AutomaticHelpers '%s' is not valid, using default value %sz9FirewallBackend '%s' is not valid, using default value %sz:FlushAllOnReload '%s' is not valid, using default value %sz6RFC3964_IPv4 '%s' is not valid, using default value %sz;AllowZoneDrifting '%s' is not valid, using default value %s)r-r.)r+r4r*r5)r+r4r*r5)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)r*r5r+r4)%ropenr Exceptionrerrorr#rZ FALLBACK_ZONEstrZFALLBACK_MINIMAL_MARKZFALLBACK_CLEANUP_ON_EXITZ FALLBACK_CLEANUP_MODULES_ON_EXITZFALLBACK_LOCKDOWNZFALLBACK_IPV6_RPFILTERZFALLBACK_INDIVIDUAL_CALLSZFALLBACK_LOG_DENIEDZFALLBACK_AUTOMATIC_HELPERSZFALLBACK_FIREWALL_BACKENDZFALLBACK_FLUSH_ALL_ON_RELOADZFALLBACK_RFC3964_IPV4ZFALLBACK_ALLOW_ZONE_DRIFTINGrlensplit valid_keysrrcloseint ValueError TypeErrorZwarninglowerZLOG_DENIED_VALUESZAUTOMATIC_HELPERS_VALUESZFIREWALL_BACKEND_VALUES)rfmsglineZpairr"rrrreadFs                                       zfirewalld_conf.readc :Cst|jdkrdSg}tjjtjs2tjtjdy.tj ddtjj |j tjj |j dd}Wn2t k r}ztjd|WYdd}~XnXd}d}ytj|j dd d }WnPt k r}z0tjj|j rtjd |j |fnd}WYdd}~Xn6Xx0|D]&}|sP|jd }t|dkrH|s2|jd d }n|ddkrpd}|j||jd n|jd}t|dkrd}|j|d q |dj} |dj} | |kr.| |jkr|j| | krd}|jd| |j| fd }n$| |jkrd }nd}|j|d |j| nd }q Wt|jdkrx^|jjD]P\} } | |krjqT| dkrxqT|s|jd d }|jd| | fd }qTW|r|j|j|stj|jdStjj|j r@ytj|j d|j WnBt k r>}z$tj|jtd|j |fWYdd}~XnXytj|j|j WnBt k r}z$tj|jtd|j |fWYdd}~XnXtj|j ddS)Nr,iZwtz%s.F)modeprefixdirdeletez!Failed to open temporary file: %sZrtzUTF-8)rFencodingzFailed to open '%s': %sr%Trr-r2r3z%s=%s rrz%s.oldzBackup of '%s' failed: %szFailed to create '%s': %si)rr) r:rospathexistsrZ ETC_FIREWALLDmkdirtempfileZNamedTemporaryFilebasenamerdirnamer7rr8ior6rwriter;rappendr&r=r!nameshutilZcopy2IOErrorZmovechmod) rdoneZ temp_filerCZmodifiedemptyrBrDpr r"rrrrSs                  $ $zfirewalld_conf.writeN) __name__ __module__ __qualname__rrrrr#r(rErSrrrrr%s r)Zos.pathrKrRrOrVZfirewallrZfirewall.core.loggerrZfirewall.functionsrrrr<objectrrrrrs  PKpge[͆ RR*io/__pycache__/policy.cpython-36.opt-1.pycnu[3 gϢ@s dddgZddljZddlZddlZddlZddlmZddlm Z m Z ddlm Z m Z m Z ddlmZmZmZdd lmZmZmZmZmZmZdd lmZdd lmZdd lmZdd lmZddZ ddZ!ddZ"ddZ#ddZ$GdddeZ%GdddeZ&dddZ'dddZ(dS) Policy policy_reader policy_writerN)config)checkIPcheckIP6)uniqifymax_policy_name_lenportStr)DEFAULT_POLICY_TARGETPOLICY_TARGETSDEFAULT_POLICY_PRIORITY) IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol)rich)log)errors) FirewallErrorc Cs|dkr n|dkrn|dkr|jr`|jjrJtjdt|jd|_dStj|d|j_dS|d|jj kr|jj j |dntjd|dn|dkrN|jr|jjrtjdt|jd|_dStj |d|d |j_dSt |dt |d t|dd |d f}||jjkr4|jjj |ntjd |d|d nN|d kr|jr|jjrtjdt|jd|_dStj|d |j_nBt|d |d |jjkr|jjj |d ntjd |d n|dkrh|jr.|jjrtjdt|jd|_dStj|d|j_dS|d|jjkrT|jjj |dntjd|dn4|dkr|jr|jjrtjdt|jd|_dStj|d|j_dStjd|dn|dkr2|jr|jjrtjdt|jd|_dStj|j_n|jjr&tjdnd|j_nj|dkrd}d|krR|d}d}d|krh|d}|jr|jjrtjdt|jd|_dStj|d|d |||j_dSt |dt |d |rt ||r t| r t| r ttjd|t|dd |d t|d t|f}||jjkrL|jjj |n6tjd|d|d |rld|nd|r|d|ndn|dkr@|jr|jjrtjdt|jd|_dStj|d|d |j_dSt |dt |d t|dd |d f}||jj kr&|jj j |ntjd|d|d n\|dkr|jsftjdd|_dS|jj!rtjd t|jdSd!}d}d"|kr|d"}d}d#|kr|d#}d$|kr|d$j"dLkrd}tj#||||j_!n|dMkr|jstjd+d|_dS|jj$r0tjd,d|_dS|d'krHtj%|j_$nh|d(krxd} d-|krh|d-} tj&| |j_$n8|d)krtj'|j_$n |d*kr|d.} tj(| |j_$|jj$|_)n|d/kr^|jstjd0dS|jjrtjd1dSd} d2|kr*|d2} | dNkr*tjd;d|_dSd<|kr<|d<nd} tj*| | |j_|jj|_)n>|d=kr|js~tjd>dS|jj+rtjd?t|jd|_dStj,|j_+|jj+|_)n|d@kr,d} dA}dB|kr|dB} | dOkrtjdE|dBd|_dSdF|krt-|dF}tj.| |dG|_np|dHkr|j)sRtjdId|_dS|j)j/rxtjdJt|jd|_dS|d }tj0||j1dK|j)_/nd!SdS)PNshort descriptionservicez;Invalid rule: More than one element in rule '%s', ignoring.Tnamez#Service '%s' already set, ignoring.portprotocol-z#Port '%s/%s' already set, ignoring.valuez$Protocol '%s' already set, ignoring.z icmp-blockz&icmp-block '%s' already set, ignoring.z icmp-typez-Invalid rule: icmp-block '%s' outside of rule masqueradez!Masquerade already set, ignoring.z forward-portzto-portzto-addrz#to-addr '%s' is not a valid addressz-Forward port %s/%s%s%s already set, ignoring.z >%sz @%sz source-portz*Source port '%s/%s' already set, ignoring. destinationz)Invalid rule: Destination outside of rulez?Invalid rule: More than one destination in rule '%s', ignoring.Faddressipsetinvertyestrueacceptrejectdropmarkz$Invalid rule: Action outside of rulez"Invalid rule: More than one actiontypesetrz!Invalid rule: Log outside of rulezInvalid rule: More than one loglevelemergalertcriterrorwarningnoticeinfodebugzInvalid rule: Invalid log levelprefixauditz#Invalid rule: Audit outside of rulez9Invalid rule: More than one audit in rule '%s', ignoring.rulerfamilyipv4ipv6z&Invalid rule: Rule family "%s" invalidpriority)r:r=limitz4Invalid rule: Limit outside of action, log and auditz9Invalid rule: More than one limit in rule '%s', ignoring.burst)r&r')r(r)r*r+)r/r0r1r2r3r4r5r6)r;r<)2_ruleelementrr3str _rule_errorr Rich_Serviceitemservicesappend Rich_Portrrr ports Rich_Protocolr protocolsRich_IcmpBlock icmp_blocks Rich_IcmpTypeRich_Masquerader Rich_ForwardPortrrrr INVALID_ADDR forward_portsRich_SourcePort source_portsr"lowerZRich_Destinationaction Rich_Accept Rich_Reject Rich_Drop Rich_Mark _limit_okZRich_Logr8Z Rich_Auditint Rich_Ruler>Z Rich_Limitget)objrattrsentryto_portZto_addrr%r#r$Z_typeZ_setr.r7r:r=rrc/usr/lib/python3.6/policy.pycommon_startElements                                                                            recCs|dkr|jsy|jjWn6tk rR}ztjd|t|jWYdd}~XnLXt|j|jjkr|jj j |j|jjj t|jntjdt|jd|_d|_n|d krd|_ dS) Nr9z%s: %sz Rule '%s' already set, ignoring.Fr(r)r*r+rr8)r(r)r*r+rr8) rCr@Zcheck Exceptionrr3rBrE rules_strrulesrGr[)r_rercrcrdcommon_endElements& rjcCst|trdnd}|dkrT|jrT|jj}x$|D]}||kr0ttjd|q0Wn|dkrx$|D]}t|dt|dqbWnb|dkrx|D] }t |qWn@|d kr|jr|jj } x$|D]} | | krttj d | qWn|d krx|D]} t| dt| d| d  r>| d  r>ttj d| | d rTt| d | d rt | d  rt| d  rttjd| d qWnT|dkrx&|D]}t|dt|dqWn|dkrx|D]} tj| d} |jr| jrt| jtjst| jtjr|jj } | jj| krLttj d | jjnH| jr|jj| jj}|jr| j|jkrttj d| j| jjfnL|jrt| jtjr|jj}| jj|krttjdj||j| jjqWdS)NrZZonerFz '%s' not among existing servicesrIrrKrMz"'%s' not among existing icmp typesrRz$'%s' is missing to-port AND to-addr z#to-addr '%s' is not a valid addressrTrg rich_rules)rule_strz3rich rule family '%s' conflicts with icmp type '%s'z){} '{}': '{}' not among existing services)rgrn) isinstancer fw_configZ get_servicesrrZINVALID_SERVICErrrZ get_icmptypesZINVALID_ICMPTYPEINVALID_FORWARDrrrQrr]rArLrNrr:Z get_icmptyper"rDformat)r_rrE all_configZobj_typeZexisting_servicesrrprotoZexisting_icmptypesZicmptypefwd_portr9Zobj_richZictrcrcrdcommon_check_config2s                      rwcCs0d|ji}|j}|dk r ||d<|jd|dS)Nrr?r>)rr? simpleElement)handlerr>dr?rcrcrd_handler_add_rich_limitxs  r{c Cs|jrF|jdkrF|jd|jdi|j|j|jd|jd|jr|jdkr|jd|jdi|j|j|jd|jdx6t|jD](}|jd|jdd|i|jdqWx@t|j D]2}|jd|jd|d |d d |jdqWx8t|j D]*}|jd|jd d |i|jdqWx8t|j D]*}|jd|jdd|i|jdqLW|j r|jd|jdi|jdxt|j D]}|jd|d |d d }|dr|ddkr|d|d<|dr|ddkr|d|d<|jd||jdqWxBt|jD]4}|jd|jd|d |d d |jdq>WxT|jD]H}i}|jr|j|d<|jd krt|j|d<|jd|jd||jd|jrVi}|jjr|jj|d<|jjr|jj|d<|jjr$|jj|d<|jjr6d|d<|jd|jd||jd|jri}|jjrx|jj|d<|jjr|jj|d<|jjrd|d<|jd|jd ||jd|jrxd} i}t|jtjkrd} |jj|d<nbt|jtjkr(d} |jj|d<|jj |d <n0t|jtj!krNd } |jj"|d <n t|jtj#krfd} nt|jtj$krd} |jj|d<nt|jtj%krd!} |jj|d<nt|jtj&krd} |jj|d<|jj |d <|jj'dkr|jj'|d<|jj(dkrX|jj(|d<nFt|jtj)krBd} |jj|d<|jj |d <nt*t+j,d"t|j|jd|j| ||jd|j-ri}|j-j.r|j-j.|d#<|j-j/r|j-j/|d$<|j-j0r|jd|jd%||jd&t1||j-j0|jd'|jd%n|jd|jd%||jd|j2ri}|j2j0rx|jd|jd(i|jd&t1||j2j0|jd'|jd(n|jd|jd(||jd|j3rd} i}t|j3tj4krd)} n|t|j3tj5krd*} |j3jr<|j3j|d+<nNt|j3tj6krd,} n6t|j3tj7kr*d-} |j3j8|d.<nt-j9d/t|j3|j3j0r|jd|j| ||jd&t1||j3j0|jd'|j| n|jd|j| ||jd|jd|jd|jdqWdS)0Nr!z r rrrrrrk)rrrrz icmp-blockr rlzto-portrmzto-addrz forward-portz source-portr:r=r9r#macr$Truer%z sourcer"z icmp-typez"Unknown element '%s' in obj_writerr7r.rz z r8r(r)r,r*r+r-zUnknown action '%s'):rignorableWhitespace startElementZ characters endElementrrrFrxrIrKrMr rRrTrhr:r=rBraddrr}r$r%r"rAr,rrDrrHrrrJrrOrLrNrPrb to_addressrSrrZINVALID_OBJECTrr7r.r>r{r8rVrWrXrYrZr-r3) r_ryrrrZicmpZforwardr`r9rArVrcrcrd common_writers\                                                                                        rcsPeZdZd7ZdZeZdgZd8d9d:d;d dgfd dgfddgfddgfdd?gfd@ddgfddgffZdddgZ dddgdgddgdgdgdddgddddgddgddddddgdgdgdgdZ ddgdd gd!dgd"d#d$d!d%gd"d$d%gd&d'gd(gd)gd*Z fd+d,Z d-d.Z fd/d0Zfd1d2Zd3d4Zfd5d6ZZS)Ariirversionr!rrtargetrFrIrMr FrRrnrKrTr= ingress_zones egress_zones_r/Nrrrrr-)rrpolicyrrz icmp-blockz icmp-typer z forward-portr9rr"rz source-portrr8r(r)r*r+r>z ingress-zonez egress-zonezto-portzto-addrr:r#r}r%r$r7r.r,r?)rz forward-portr9rr"rr)r>cstt|jd|_d|_d|_t|_g|_g|_ g|_ g|_ d|_ g|_ g|_d|_g|_g|_d|_|j|_d|_g|_g|_dS)Nr!F)superr__init__rrrr rrFrIrKrMr rRrTrqrhrgappliedpriority_defaultr=Zderived_from_zonerr)self) __class__rcrdrs(zPolicy.__init__cCsd|_d|_d|_t|_|jdd=|jdd=|jdd=|jdd=d|_ |j dd=|j dd=d|_ |j dd=|jdd=d|_|j|_|jdd=|jdd=dS)Nr!F)rrrr rrFrIrKrMr rRrTrqrhrgrrr=rr)rrcrcrdcleanups$         zPolicy.cleanupcs"|dkr|jSttt||SdS)Nrn)rggetattrrr)rr)rrcrd __getattr__szPolicy.__getattr__csB|dkr,dd|D|_dd|jD|_ntt|j||dS)NrncSsg|]}tj|dqS))ro)rr]).0srcrcrd sz&Policy.__setattr__..cSsg|] }t|qSrc)rB)rrrcrcrdrs)rhrgrr __setattr__)rrr)rrcrdrszPolicy.__setattr__c Cst|||||dkr2|tkr.ttjd|n|dkrz||jksX||jksX||jkrvttjd||j|j|jfn|dkrhddg}|j r||j j 7}x|D]}||krttj d ||dkrt ddgt |@s|dkrt |t |grttj d ||dkr|dkr8d|kr8d|dksT|dkrd|krd|dkrttj d qWn|d kr|rd|krd|dkrttj d nxd|krd|dkrttj dxR|dD]F}|dkrސq|j j |}|j rd|j j|krttj dqWn|dkr4x|D]}tj|d}|jrt|jtjrd|kr|d|dkr|ttj d nxd|kr,d|dkrttj dxR|dD]F}|dkrq|j j |}|j rd|j j|krttj dqWq,|jrt|jtjrd|kr,d|dkr@|jjrttjdnt|dr,|jjs`ttjdd|dkr,x|dD]8}|j j |}|j rxd|j j|krxttj dqxWnv|jr,t|jtjr,d|kr,xR|dD]F}|dkrq|j j |}|j rd|j j|krttj dqWq,Wn|dkrx|D]} d|krnd|dkrnttj dnd|krDd|dkr| drttjdnt|drD| dsttjdd|dkrDxD|dD]8}|j j |}|j rd|j j|krttj dqWqDWdS)Nrz'%s' is invalid targetr=zQ%d is invalid priority. Must be in range [%d, %d]. The following are reserved: %srrANYHOSTz'%s' not among existing zonesz>'%s' may only contain one of: many regular zones, ANY, or HOSTzF'HOST' can only appear in either ingress or egress zones, but not bothr z.'masquerade' is invalid for egress zone 'HOST'z/'masquerade' is invalid for ingress zone 'HOST'Z interfaceszR'masquerade' cannot be used in a policy if an ingress zone has assigned interfacesrn)rozAA 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'zC'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zonezS'forward-port' cannot be used in a policy if an egress zone has assigned interfaceszR'mark' action cannot be used in a policy if an egress zone has assigned interfacesrRz1'forward-port' is invalid for ingress zone 'HOST'rm)rr)rr)rr)rr)rwr rrINVALID_TARGETpriority_reserved priority_max priority_minZINVALID_PRIORITYrq get_zonesZ INVALID_ZONEr-Zget_zoneZget_zone_config_dictrr]rArprOrPrrrrVrZ) rrrErtZexisting_zoneszoneZz_objr9r_rvrcrcrd _check_configs       "                           zPolicy._check_configcstt|j||jdr,ttjd|n|jdrHttjd|n|jddkrhttjd|njd|kr|d|j d}n|}t |t krttjd|t |t f|j r||j j krttjddS)Nrz'%s' can't start with '/'z'%s' can't end with '/'rkzmore than one '/' in '%s'z&Policy of '%s' has %d chars, max is %dz,Policies can't have the same name as a zone.)rr check_name startswithrr INVALID_NAMEendswithcountfindlenr rqrZ NAME_CONFLICT)rrZ checked_name)rrcrdr,s*      zPolicy.check_namei)rr!)rr!)rr!)rr!)r!r!)r F)r!r!r!r!)r!r!)r=r)__name__ __module__ __qualname__rrr rrZIMPORT_EXPORT_STRUCTUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrrrrrr __classcell__rcrc)rrdrZsr        ^c@s$eZdZddZddZddZdS)policy_ContentHandlercCs"tj||d|_d|_d|_dS)NF)rrr@rCr[)rrErcrcrdrHs zpolicy_ContentHandler.__init__cCstj||||jrdS|jj||t|||r6dS|dkrd|krR|d|j_d|krjt|d|j_d|kr|d}|t krt t j ||r||j_ n^|dkr|d|jjkr|jjj|dntjd|dn|dkr |d|jjkr|jjj|dntjd |dn|d kr|jsFtjd d |_dS|jjrltjd t|jd |_dSd}d|kr|djdkrd }d}}}d|kr|d}d|kr|d}d|kr|d}tj||||d|j_dStjd|dSdS)Nrrr=rz ingress-zonerz(Ingress zone '%s' already set, ignoring.z egress-zonez'Egress zone '%s' already set, ignoring.rz$Invalid rule: Source outside of ruleTz:Invalid rule: More than one source in rule '%s', ignoring.Fr%r&r'r#r}r$)r%zUnknown XML element '%s')r&r')rrrCrEZparser_check_element_attrsrerr\r=r rrrrrrGrr3rr@rrBrUrZ Rich_Source)rrr`rr%rr}r$rcrcrdrNsf                 z"policy_ContentHandler.startElementcCstj||t||dS)N)rrrj)rrrcrcrdrs z policy_ContentHandler.endElementN)rrrrrrrcrcrcrdrGs@rFc Cst}|jds ttjd||dd |_|s>|j|j||_||_|j t j rZdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r} zttjd| jWYdd} ~ XnXWdQRX~~|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid policy file: %s)rrrrrrrfilenamepathrr ETC_FIREWALLDZbuiltindefaultrsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_POLICYZ getException) rrZ no_check_namerryparserrfrmsgrcrcrdrs6        (c Cs|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|j|jkr0t|j|d <|j|d <|jd ||jdt||x8t|jD]*} |jd|jdd| i|jdqfWx8t|jD]*} |jd|jdd| i|jdqW|jd |jd|j |j!~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingr!rr=rrr|z z ingress-zonerz egress-zone)"rrrosexistsshutilZcopy2rfrr2dirnamerrrmkdiriorrZ startDocumentrr=rrBrrrrrrrxrrZ endDocumentclose) rr_pathrrdirpathrryr`rrcrcrdrsN             )F)N))__all__Zxml.saxrrrrZfirewallrZfirewall.functionsrrrr r Zfirewall.core.baser r r Zfirewall.core.io.io_objectrrrrrrZ firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrerjrwr{rrrrrrcrcrcrds4        F[nL PKpge[x++)io/__pycache__/ipset.cpython-36.opt-1.pycnu[3 gR@sdZdddgZddljZddlZddlZddlZddlmZddl m Z m Z m Z m Z mZmZmZmZmZddlmZmZmZmZdd lmZmZdd lmZmZmZmZdd l m!Z!dd lm"Z"dd l#m$Z$GdddeZ%GdddeZ&ddZ'dddZ(dS)z$ipset io XML handler, reader, writerIPSet ipset_reader ipset_writerN)config) checkIPcheckIP6 checkIPnMask checkIP6nMask u2b_if_py2 check_mac check_portcheckInterface checkProtocol)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator) IPSET_TYPESIPSET_CREATE_OPTIONS)check_icmp_namecheck_icmp_typecheck_icmpv6_namecheck_icmpv6_type)log)errors) FirewallErrorcseZdZddd d!dddifddgffZdZd d d d gZd d dgdgd dZdgdgdZfddZddZ ddZ e ddZ ddZ fddZZS)"rversionshort descriptiontypeoptionsentriesz (ssssa{ss}as)_-:.Nname)rripsetoptionentryvalue)r(r)cs<tt|jd|_d|_d|_d|_g|_i|_d|_ dS)NrF) superr__init__rrrr r"r!applied)self) __class__/usr/lib/python3.6/ipset.pyr-CszIPSet.__init__cCs8d|_d|_d|_d|_|jdd=|jjd|_dS)NrF)rrrr r"r!clearr.)r/r1r1r2cleanupMs  z IPSet.cleanupcCs\t|j|_t|j|_t|j|_t|j|_dd|jjD|_dd|jD|_dS)z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSsi|]\}}t|t|qSr1)r ).0kvr1r1r2 ^sz(IPSet.encode_strings..cSsg|] }t|qSr1)r )r5er1r1r2 `sz(IPSet.encode_strings..N)r rrrr r!itemsr")r/r1r1r2encode_stringsVs    zIPSet.encode_stringsc Csd}d|kr|ddkrd}|jds6ttjd||ddjd}|jd}t|t|ksnt|d krttjd ||fxztt|D]h}||}||}|d krd |ko|dkrh|d krttjd |||f|jd } t| dkrttjd||||fx| D]J} |dkr2t|  sH|dkrt |  rttjd| |||fqWnh|dkr|dkrttjd||||f|dkrt } nt} nt } | |sttjd||||fq|dkr@d |kr|jd } t| dkrttjd||||f|dkr0t| d sJ|dkrft | d rfttjd| d|||f|dkrt | d  s|dkr>t | d  r>ttjd| d |||fn|j dr|dko|dko|dksttjd||||f|dkrt | s&|dkrt | rttjd||||fq|dkrvt | s`|dkrttjd||fq|dkrd|kr|jd} t| dkrttjd|| ddkr|dkrttjd||ft| d  rt| d  rttjd| d |fn| dd1kr~|dkrDttjd||ft| d  rt| d  rttjd!| d |fn^| dd2krt| d rttjd&| d|fn&t| d sttjd'| d |fnt|sttjd(||fq|d)kr|jd*rPyt|d+} Wn*tk rLttjd,||fYnXn8y t|} Wn*tk rttjd,||fYnX| dks| d-krttjd,||fq|d.krt| st|d/krttjd0||fqttjd|qWdS)3NZipv4familyinet6Zipv6zhash:zipset type '%s' not usable,z)entry '%s' does not match ipset type '%s'Zipr$z invalid address '%s' in '%s'[%d]z.invalid address range '%s' in '%s' for %s (%s)z(invalid address '%s' in '%s' for %s (%s)z0.0.0.0rZnetz/0zhash:net,ifaceZmacz00:00:00:00:00:00z invalid mac address '%s' in '%s'Zportr%zinvalid port '%s'Zicmpz(invalid protocol for family '%s' in '%s'zinvalid icmp type '%s' in '%s'icmpv6 ipv6-icmpz invalid icmpv6 type '%s' in '%s'tcpsctpudpudplitezinvalid protocol '%s' in '%s'zinvalid port '%s'in '%s'zinvalid port '%s' in '%s'ZmarkZ0xzinvalid mark '%s' in '%s'lZifacezinvalid interface '%s' in '%s')rCrD)rErFrGrH) startswithrr INVALID_IPSETsplitlenZ INVALID_ENTRYrangerrrr endswithr rrrrrr int ValueErrorr ) r*r!Z ipset_typer=flagsr;iflagitemZsplitsZ_splitZip_checkZint_valr1r1r2 check_entrybs@                                zIPSet.check_entrycCs|dkr |tkr ttjd||dkrx|jD]}|tkrNttjd||dkryt||}Wn,tk rttj d|||fYnX|d krttj d |||fq2|d kr2||dkr2ttj ||q2WdS)Nr z'%s' is not valid ipset typer!zipset invalid option '%s'timeouthashsizemaxelemz)Option '%s': Value '%s' is not an integerrz#Option '%s': Value '%s' is negativer=inetr>)rXrYrZ)r[r>) rrr INVALID_TYPEkeysrrLrQrR INVALID_VALUEINVALID_FAMILY)r/rrVZ all_configkey int_valuer1r1r2 _check_configs2   zIPSet._check_configcsrd|dkr6|dddkr6t|ddkr6ttjx&|dD]}tj||d|dq@Wtt|j|dS)NrX0r?r)rNrrZIPSET_WITH_TIMEOUTrrWr, import_config)r/rr*)r0r1r2rf3s  zIPSet.import_config)rr)rr)rr)r r)__name__ __module__ __qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSr-r4r< staticmethodrWrbrf __classcell__r1r1)r0r2r,s,       7c@seZdZddZddZdS)ipset_ContentHandlerc Cstj||||jj|||dkrpd|krX|dtkrLttjd|d|d|j_d|krl|d|j_ nz|dkr|nn|dkrnb|dkrd}d |kr|d }|d dkrttj d|d |jjdko|d dkrttj d|d |jjf|d dkr&| r&ttj d|d |d dkry t |}Wn.t k rnttj d|d |fYnX|dkrttj d|d |f|d d kr|dkrttj||d |jjkr||jj|d <ntjd|d dS)Nr(r z%srrrr)rr+r'r=rXrYrZzUnknown option '%s'zhash:macz%Unsupported option '%s' for type '%s'z&Missing mandatory value of option '%s'z)Option '%s': Value '%s' is not an integerrz#Option '%s': Value '%s' is negativer[r>z Option %s already set, ignoring.)r=rXrYrZ)r=)r=rXrYrZ)rXrYrZ)r[r>)r startElementrVZparser_check_element_attrsrrrr\r rZINVALID_OPTIONrQrRr^r_r!rwarning)r/r'attrsr+rar1r1r2rm>sd      z!ipset_ContentHandler.startElementcCs(tj|||dkr$|jjj|jdS)Nr*)r endElementrVr"appendZ_element)r/r'r1r1r2rpus zipset_ContentHandler.endElementN)rgrhrirmrpr1r1r1r2rl=s7rlc %Cst}|jds ttjd||dd|_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~d |jkrF|jd d krFt|jd krFtjd |j|jdd=d } t} x| t|jkr|j| | krtjd |j| |jj| nry|j |j| |j|j!Wn<tk r} ztjd| |jj| WYdd} ~ XnX| j"|j| | d7} qRW~ t#r|j$|S)Nz.xmlz'%s' is missing .xml suffixrcFTz%s/%srbznot a valid ipset file: %srXrdrz6ipset '%s': timeout option is set, entries are ignoredzEntry %s already set, ignoring.z %s, ignoring.rA)%rrPrrZ INVALID_NAMEr'Z check_namefilenamepathrKr ETC_FIREWALLDZbuiltindefaultrlsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionrLZ getExceptionr!rNr"rrnsetpoprWr addrr<) rtrur(handlerparserr'fsourcemsgrTZ entries_setr9r1r1r2rzs^        (  c Cs|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|jd |ji}|jr|jd kr|j|d <|jd ||jd |jrz|jd krz|jd|jdi|j|j|jd|jd |jr|jd kr|jd|jdi|j|j|jd|jd xZ|jjD]L\} } |jd| d kr|jd| | dn|jdd| i|jd qWxD|jD]:} |jd|jdi|j| |jd|jd q(W|jd |jd |j|j ~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingr rrr( z rrr))r'r+r'r*)!rurtr'osexistsshutilZcopy2 ExceptionrerrordirnamerKrrvmkdirioryrZ startDocumentr rrmZignorableWhitespacerZ charactersrprr!r;Z simpleElementr"Z endDocumentclose) r(ru_pathr'rdirpathrr~ror`r+r*r1r1r2rsf                           )N))__doc____all__Zxml.saxrxrrrZfirewallrZfirewall.functionsrrrr r r r r rZfirewall.core.io.io_objectrrrrZfirewall.core.ipsetrrZfirewall.core.icmprrrrZfirewall.core.loggerrrZfirewall.errorsrrrlrrr1r1r1r2s&   ,   =5PKpge[x++#io/__pycache__/ipset.cpython-36.pycnu[3 gR@sdZdddgZddljZddlZddlZddlZddlmZddl m Z m Z m Z m Z mZmZmZmZmZddlmZmZmZmZdd lmZmZdd lmZmZmZmZdd l m!Z!dd lm"Z"dd l#m$Z$GdddeZ%GdddeZ&ddZ'dddZ(dS)z$ipset io XML handler, reader, writerIPSet ipset_reader ipset_writerN)config) checkIPcheckIP6 checkIPnMask checkIP6nMask u2b_if_py2 check_mac check_portcheckInterface checkProtocol)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator) IPSET_TYPESIPSET_CREATE_OPTIONS)check_icmp_namecheck_icmp_typecheck_icmpv6_namecheck_icmpv6_type)log)errors) FirewallErrorcseZdZddd d!dddifddgffZdZd d d d gZd d dgdgd dZdgdgdZfddZddZ ddZ e ddZ ddZ fddZZS)"rversionshort descriptiontypeoptionsentriesz (ssssa{ss}as)_-:.Nname)rripsetoptionentryvalue)r(r)cs<tt|jd|_d|_d|_d|_g|_i|_d|_ dS)NrF) superr__init__rrrr r"r!applied)self) __class__/usr/lib/python3.6/ipset.pyr-CszIPSet.__init__cCs8d|_d|_d|_d|_|jdd=|jjd|_dS)NrF)rrrr r"r!clearr.)r/r1r1r2cleanupMs  z IPSet.cleanupcCs\t|j|_t|j|_t|j|_t|j|_dd|jjD|_dd|jD|_dS)z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSsi|]\}}t|t|qSr1)r ).0kvr1r1r2 ^sz(IPSet.encode_strings..cSsg|] }t|qSr1)r )r5er1r1r2 `sz(IPSet.encode_strings..N)r rrrr r!itemsr")r/r1r1r2encode_stringsVs    zIPSet.encode_stringsc Csd}d|kr|ddkrd}|jds6ttjd||ddjd}|jd}t|t|ksnt|d krttjd ||fxztt|D]h}||}||}|d krd |ko|dkrh|d krttjd |||f|jd } t| dkrttjd||||fx| D]J} |dkr2t|  sH|dkrt |  rttjd| |||fqWnh|dkr|dkrttjd||||f|dkrt } nt} nt } | |sttjd||||fq|dkr@d |kr|jd } t| dkrttjd||||f|dkr0t| d sJ|dkrft | d rfttjd| d|||f|dkrt | d  s|dkr>t | d  r>ttjd| d |||fn|j dr|dko|dko|dksttjd||||f|dkrt | s&|dkrt | rttjd||||fq|dkrvt | s`|dkrttjd||fq|dkrd|kr|jd} t| dkrttjd|| ddkr|dkrttjd||ft| d  rt| d  rttjd| d |fn| dd1kr~|dkrDttjd||ft| d  rt| d  rttjd!| d |fn^| dd2krt| d rttjd&| d|fn&t| d sttjd'| d |fnt|sttjd(||fq|d)kr|jd*rPyt|d+} Wn*tk rLttjd,||fYnXn8y t|} Wn*tk rttjd,||fYnX| dks| d-krttjd,||fq|d.krt| st|d/krttjd0||fqttjd|qWdS)3NZipv4familyinet6Zipv6zhash:zipset type '%s' not usable,z)entry '%s' does not match ipset type '%s'Zipr$z invalid address '%s' in '%s'[%d]z.invalid address range '%s' in '%s' for %s (%s)z(invalid address '%s' in '%s' for %s (%s)z0.0.0.0rZnetz/0zhash:net,ifaceZmacz00:00:00:00:00:00z invalid mac address '%s' in '%s'Zportr%zinvalid port '%s'Zicmpz(invalid protocol for family '%s' in '%s'zinvalid icmp type '%s' in '%s'icmpv6 ipv6-icmpz invalid icmpv6 type '%s' in '%s'tcpsctpudpudplitezinvalid protocol '%s' in '%s'zinvalid port '%s'in '%s'zinvalid port '%s' in '%s'ZmarkZ0xzinvalid mark '%s' in '%s'lZifacezinvalid interface '%s' in '%s')rCrD)rErFrGrH) startswithrr INVALID_IPSETsplitlenZ INVALID_ENTRYrangerrrr endswithr rrrrrr int ValueErrorr ) r*r!Z ipset_typer=flagsr;iflagitemZsplitsZ_splitZip_checkZint_valr1r1r2 check_entrybs@                                zIPSet.check_entrycCs|dkr |tkr ttjd||dkrx|jD]}|tkrNttjd||dkryt||}Wn,tk rttj d|||fYnX|d krttj d |||fq2|d kr2||dkr2ttj ||q2WdS)Nr z'%s' is not valid ipset typer!zipset invalid option '%s'timeouthashsizemaxelemz)Option '%s': Value '%s' is not an integerrz#Option '%s': Value '%s' is negativer=inetr>)rXrYrZ)r[r>) rrr INVALID_TYPEkeysrrLrQrR INVALID_VALUEINVALID_FAMILY)r/rrVZ all_configkey int_valuer1r1r2 _check_configs2   zIPSet._check_configcsrd|dkr6|dddkr6t|ddkr6ttjx&|dD]}tj||d|dq@Wtt|j|dS)NrX0r?r)rNrrZIPSET_WITH_TIMEOUTrrWr, import_config)r/rr*)r0r1r2rf3s  zIPSet.import_config)rr)rr)rr)r r)__name__ __module__ __qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSr-r4r< staticmethodrWrbrf __classcell__r1r1)r0r2r,s,       7c@seZdZddZddZdS)ipset_ContentHandlerc Cstj||||jj|||dkrpd|krX|dtkrLttjd|d|d|j_d|krl|d|j_ nz|dkr|nn|dkrnb|dkrd}d |kr|d }|d dkrttj d|d |jjdko|d dkrttj d|d |jjf|d dkr&| r&ttj d|d |d dkry t |}Wn.t k rnttj d|d |fYnX|dkrttj d|d |f|d d kr|dkrttj||d |jjkr||jj|d <ntjd|d dS)Nr(r z%srrrr)rr+r'r=rXrYrZzUnknown option '%s'zhash:macz%Unsupported option '%s' for type '%s'z&Missing mandatory value of option '%s'z)Option '%s': Value '%s' is not an integerrz#Option '%s': Value '%s' is negativer[r>z Option %s already set, ignoring.)r=rXrYrZ)r=)r=rXrYrZ)rXrYrZ)r[r>)r startElementrVZparser_check_element_attrsrrrr\r rZINVALID_OPTIONrQrRr^r_r!rwarning)r/r'attrsr+rar1r1r2rm>sd      z!ipset_ContentHandler.startElementcCs(tj|||dkr$|jjj|jdS)Nr*)r endElementrVr"appendZ_element)r/r'r1r1r2rpus zipset_ContentHandler.endElementN)rgrhrirmrpr1r1r1r2rl=s7rlc %Cst}|jds ttjd||dd|_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~d |jkrF|jd d krFt|jd krFtjd |j|jdd=d } t} x| t|jkr|j| | krtjd |j| |jj| nry|j |j| |j|j!Wn<tk r} ztjd| |jj| WYdd} ~ XnX| j"|j| | d7} qRW~ t#r|j$|S)Nz.xmlz'%s' is missing .xml suffixrcFTz%s/%srbznot a valid ipset file: %srXrdrz6ipset '%s': timeout option is set, entries are ignoredzEntry %s already set, ignoring.z %s, ignoring.rA)%rrPrrZ INVALID_NAMEr'Z check_namefilenamepathrKr ETC_FIREWALLDZbuiltindefaultrlsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionrLZ getExceptionr!rNr"rrnsetpoprWr addrr<) rtrur(handlerparserr'fsourcemsgrTZ entries_setr9r1r1r2rzs^        (  c Cs|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|jd |ji}|jr|jd kr|j|d <|jd ||jd |jrz|jd krz|jd|jdi|j|j|jd|jd |jr|jd kr|jd|jdi|j|j|jd|jd xZ|jjD]L\} } |jd| d kr|jd| | dn|jdd| i|jd qWxD|jD]:} |jd|jdi|j| |jd|jd q(W|jd |jd |j|j ~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingr rrr( z rrr))r'r+r'r*)!rurtr'osexistsshutilZcopy2 ExceptionrerrordirnamerKrrvmkdirioryrZ startDocumentr rrmZignorableWhitespacerZ charactersrprr!r;Z simpleElementr"Z endDocumentclose) r(ru_pathr'rdirpathrr~ror`r+r*r1r1r2rsf                           )N))__doc____all__Zxml.saxrxrrrZfirewallrZfirewall.functionsrrrr r r r r rZfirewall.core.io.io_objectrrrrZfirewall.core.ipsetrrZfirewall.core.icmprrrrZfirewall.core.loggerrrZfirewall.errorsrrrlrrr1r1r1r2s&   ,   =5PKpge[>#io/__pycache__/ifcfg.cpython-36.pycnu[3 g@s^dZdgZddlZddlZddlZddlZddlmZddl m Z m Z m Z Gddde ZdS)zifcfg file parserifcfgN)log)b2uu2bPY2c@sLeZdZddZddZddZddZd d Zd d Zd dZ ddZ dS)rcCsi|_g|_||_|jdS)N)_config_deletedfilenameclear)selfr r /usr/lib/python3.6/ifcfg.py__init__#szifcfg.__init__cCsi|_g|_dS)N)rr)r r r r r )sz ifcfg.clearcCs|jjdS)N)rr )r r r r cleanup-sz ifcfg.cleanupcCs|jj|jS)N)rgetstrip)r keyr r r r0sz ifcfg.getcCs8t|j}t|j|j|<||jkr4|jj|dS)N)rrrrremove)r rvalueZ_keyr r r set3s  z ifcfg.setcCsHd}x2|jjD]$\}}|r$|d7}|d||f7}qWtrDt|S|S)N z%s=%s)ritemsrr)r srrr r r __str__9s z ifcfg.__str__cCsB|jyt|jd}Wn4tk rL}ztjd|j|WYdd}~XnXx|D]}|s^P|j}t|dksT|ddkrqTdd|jd dD}t|d krqTt|dd kr|dj d r|dj d r|ddd|d<|dd krqTn,|j j |ddk r tj d |j|jqT|d|j |d<qTW|jdS)NrzFailed to load '%s': %sr#;cSsg|] }|jqSr )r).0xr r r Qszifcfg.read..="rz%%s: Duplicate option definition: '%s')rr)r openr Exceptionrerrorrlensplit startswithendswithrrZwarningclose)r fmsglineZpairr r r readBs2   z ifcfg.readc :Cst|jdkrdSg}y.tjddtjj|jtjj|jdd}Wn2t k rv}zt j d|WYdd}~XnXd}d}yt j |jddd }WnNt k r}z0tjj|jrt j d |j|fnd}WYdd}~XndXx^|D]T}|sP|jd }t|dkr(|sD|jd d }q|d dkrPd}|j||jd q|jdd}t|dkr~d}|j|d q|d j} |dj} t| dkr| jdr| jdr| dd} | |kr@| |jkr|j| | krd}|jd| |j| fd }n$| |jkr"d }nd}|j|d |j| qd }qWt|jd krxF|jjD]8\} } | |krzqd|sd }|jd| | fd }qdW|r|j|j|stj|jdStjj|jr8ytj|jd|jWnBt k r6}z$tj|jtd|j|fWYdd}~XnXytj|j|jWnBt k r}z$tj|jtd|j|fWYdd}~XnXtj|jddS)NrZwtz%s.F)modeprefixdirdeletez!Failed to open temporary file: %sZrtzUTF-8)r2encodingzFailed to open '%s': %srTrrr"r#r$z%s=%s z%s.bakzBackup of '%s' failed: %szFailed to create '%s': %sir%)r)rtempfileZNamedTemporaryFileospathbasenamer dirnamer'rr(ior&existsrwriter*r+r,rappendrr-rnameshutilZcopy2IOErrorZmovechmod) r doneZ temp_filer/Zmodifiedemptyr.r0prrr r r r>_s               $ $z ifcfg.writeN) __name__ __module__ __qualname__rr rrrrr1r>r r r r r"s )__doc____all__Zos.pathr8r<r7rAZfirewall.core.loggerrZfirewall.functionsrrrobjectrr r r r s PKpge[I}h%h%0io/__pycache__/lockdown_whitelist.cpython-36.pycnu[3 g1@sddljZddlZddlZddlZddlmZddlmZm Z m Z m Z ddl m Z ddlmZmZmZmZmZmZddlmZddlmZGdd d e ZGd d d e ZdS) N)config)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)log)uniqify checkUsercheckUid checkCommand checkContext u2b_if_py2)errors) FirewallErrorc@seZdZddZddZdS)!lockdown_whitelist_ContentHandlercCstj||d|_dS)NF)r__init__ whitelist)selfitemr(/usr/lib/python3.6/lockdown_whitelist.pyr%s z*lockdown_whitelist_ContentHandler.__init__c CsVtj||||jj|||dkr@|jr6ttjdd|_n|dkrr|js\tj ddS|d}|jj |n|dkr|jstj ddSd |kryt |d }Wn&t k rtj d |d dSX|jj |nd|kr|jj|dn\|d kr@|jstj d dSd |kr.tj ddS|jj|d ntj d|dSdS)NrzMore than one whitelist.Tcommandz)Parse Error: command outside of whitelistnameuserz&Parse Error: user outside of whitelistidz"Parse Error: %s is not a valid uidselinuxz)Parse Error: selinux outside of whitelistcontextzParse Error: no contextzUnknown XML element %s)r startElementrZparser_check_element_attrsrrrZ PARSE_ERRORrerror add_commandint ValueErroradd_uidadd_user add_context)rrZattrsruidrrrr)sJ        z.lockdown_whitelist_ContentHandler.startElementN)__name__ __module__ __qualname__rrrrrrr$srcs4eZdZdZddgfddgfddgfddgffZdZd gZd d gd d gd Zddd giZfddZ ddZ ddZ ddZ ddZ ddZddZddZd d!Zd"d#Zd$d%Zd&d'Zd(d)Zd*d+Zd,d-Zd.d/Zd0d1Zd2d3Zd4d5Zd6d7Zd8d9Zd:d;Zdd?Z d@dAZ!dBdCZ"Z#S)DLockdownWhitelistz LockdownWhitelist class commandscontextsusersuidsrz (asasasai)_Nrr)rrrrrrcs6tt|j||_d|_g|_g|_g|_g|_dS)N) superr)rfilenameparserr*r,r-r.)rr1) __class__rrrnszLockdownWhitelist.__init__cCs|d kr.x|D]}|j||dd |qWnv|dkrLt|sttj|nX|dkrjt|sttj|n:|dkrt|sttj|n|d krt |sttj |dS) Nr*r,r-r.rrrr%)r*r,r-r.) _check_configr rrINVALID_COMMANDr INVALID_CONTEXTr INVALID_USERr INVALID_UID)rrrZ all_configxrrrr6ys zLockdownWhitelist._check_configcCs4|jdd=|jdd=|jdd=|jdd=dS)N)r*r,r-r.)rrrrcleanups   zLockdownWhitelist.cleanupcCs:dd|jD|_dd|jD|_dd|jD|_dS)z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSsg|] }t|qSr)r ).0r;rrr sz4LockdownWhitelist.encode_strings..cSsg|] }t|qSr)r )r=r;rrrr>scSsg|] }t|qSr)r )r=r;rrrr>sN)r*r,r-)rrrrencode_stringssz LockdownWhitelist.encode_stringscCs@t|sttj|||jkr,|jj|nttjd|dS)Nz!Command "%s" already in whitelist)r rrr7r*appendALREADY_ENABLED)rrrrrrs   zLockdownWhitelist.add_commandcCs,||jkr|jj|nttjd|dS)NzCommand "%s" not in whitelist.)r*removerr NOT_ENABLED)rrrrrremove_commands z LockdownWhitelist.remove_commandcCs ||jkS)N)r*)rrrrr has_commandszLockdownWhitelist.has_commandcCsBx<|jD]2}|jdr.|j|ddr:dSq||krdSqWdS)N*r4TFr5)r*endswith startswith)rrZ_commandrrr match_commands  zLockdownWhitelist.match_commandcCs|jS)N)r*)rrrr get_commandsszLockdownWhitelist.get_commandscCsDt|sttjt|||jkr0|jj|nttjd|dS)NzUid "%s" already in whitelist)r rrr:strr.r@rA)rr%rrrr"s  zLockdownWhitelist.add_uidcCs,||jkr|jj|nttjd|dS)NzUid "%s" not in whitelist.)r.rBrrrC)rr%rrr remove_uids zLockdownWhitelist.remove_uidcCs ||jkS)N)r.)rr%rrrhas_uidszLockdownWhitelist.has_uidcCs ||jkS)N)r.)rr%rrr match_uidszLockdownWhitelist.match_uidcCs|jS)N)r.)rrrrget_uidsszLockdownWhitelist.get_uidscCs@t|sttj|||jkr,|jj|nttjd|dS)NzUser "%s" already in whitelist)r rrr9r-r@rA)rrrrrr#s   zLockdownWhitelist.add_usercCs,||jkr|jj|nttjd|dS)NzUser "%s" not in whitelist.)r-rBrrrC)rrrrr remove_users zLockdownWhitelist.remove_usercCs ||jkS)N)r-)rrrrrhas_userszLockdownWhitelist.has_usercCs ||jkS)N)r-)rrrrr match_userszLockdownWhitelist.match_usercCs|jS)N)r-)rrrr get_usersszLockdownWhitelist.get_userscCs@t|sttj|||jkr,|jj|nttjd|dS)Nz!Context "%s" already in whitelist)r rrr8r,r@rA)rrrrrr$"s   zLockdownWhitelist.add_contextcCs,||jkr|jj|nttjd|dS)NzContext "%s" not in whitelist.)r,rBrrrC)rrrrrremove_context,s z LockdownWhitelist.remove_contextcCs ||jkS)N)r,)rrrrr has_context3szLockdownWhitelist.has_contextcCs ||jkS)N)r,)rrrrr match_context6szLockdownWhitelist.match_contextcCs|jS)N)r,)rrrr get_contexts9szLockdownWhitelist.get_contextscCs|j|jjds&ttjd|jt|}tj}|j |y|j |jWn8tj k r}zttj d|j WYdd}~XnX~~tr|jdS)Nz.xmlz'%s' is missing .xml suffixzNot a valid file: %s)r<r1rGrrZ INVALID_NAMErsaxZ make_parserZsetContentHandlerparseZSAXParseExceptionZ INVALID_TYPEZ getExceptionrr?)rhandlerr2msgrrrread>s"   zLockdownWhitelist.readcCstjj|jr\ytj|jd|jWn4tk rZ}ztd|j|fWYdd}~XnXtjjtj sxtj tj dt j |jddd}t |}|j|jdi|jdx6t|jD](}|jd |jd d |i|jdqWx:t|jD],}|jd |jd d t|i|jdqWx8t|jD]*}|jd |jd d |i|jdq0Wx8t|jD]*}|jd |jdd|i|jdqjW|jd|jd|j|j~dS)Nz%s.oldzBackup of '%s' failed: %siZwtzUTF-8)modeencodingr z rrrrrr)ospathexistsr1shutilZcopy2 ExceptionIOErrorrZ ETC_FIREWALLDmkdirioopenrZ startDocumentrZignorableWhitespacerr*Z simpleElementr.rKr-r,Z endElementZ endDocumentclose)rr[frZrr%rrrrrwriteQsB$         zLockdownWhitelist.write)$r&r'r(__doc__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr6r<r?rrDrErIrJr"rLrMrNrOr#rPrQrRrSr$rTrUrVrWr\rk __classcell__rr)r3rr)WsL         1 r))Zxml.saxrXr`rgrcZfirewallrZfirewall.core.io.io_objectrrrrZfirewall.core.loggerrZfirewall.functionsrr r r r r rZfirewall.errorsrrr)rrrrs      3PKpge[*;]q -io/__pycache__/functions.cpython-36.opt-1.pycnu[3 gy@sddlZddlmZddlmZddlmZddlmZddl m Z ddl m Z ddl mZdd lmZdd lmZdd lmZdd lmZdd lmZddZdS)N)config) FirewallError)FirewallConfig) zone_reader)service_reader) ipset_reader)icmptype_reader) helper_reader) policy_reader)Direct)LockdownWhitelist)firewalld_confc -Cs|t|}t|jtjtjgdt|jtjtj gdt |j tj tj gdt|jtjtjgdt|jtjtjgdt|jtjtjgdd}x |jD]}x||dD]}tjj|sqxttj|D]}|j dryD||d||}|d kr||_!|j"|j#||d|Wqt$k rT}zt$|j%d ||j&fWYdd}~Xqt'k r}zt'd ||fWYdd}~XqXqWqWqWtjj(tj)r:y$t*tj)}|j+|j,|j-Wnpt$k r}zt$|j%d tj)|j&fWYdd}~Xn6t'k r8}zt'd tj)|fWYdd}~XnXtjj(tj.ry$t/tj.}|j+|j,|j-Wnpt$k r}zt$|j%d tj.|j&fWYdd}~Xn6t'k r}zt'd tj.|fWYdd}~XnXtjj(tj0rxyt1tj0}|j+Wnpt$k rB}zt$|j%d tj0|j&fWYdd}~Xn6t'k rv}zt'd tj0|fWYdd}~XnXdS) N)readeradddirs)ZipsethelperZicmptypeZservicezonepolicyrz.xmlrrrrz'%s': %s)rr)2rrZ add_ipsetrZFIREWALLD_IPSETSZETC_FIREWALLD_IPSETSr Z add_helperZFIREWALLD_HELPERSZETC_FIREWALLD_HELPERSrZ add_icmptypeZFIREWALLD_ICMPTYPESZETC_FIREWALLD_ICMPTYPESrZ add_serviceZFIREWALLD_SERVICESZETC_FIREWALLD_SERVICESrZadd_zoneZFIREWALLD_ZONESZETC_FIREWALLD_ZONESr Zadd_policy_objectZFIREWALLD_POLICIESZETC_FIREWALLD_POLICIESkeysospathisdirsortedlistdirendswith fw_configZcheck_config_dictZexport_config_dictrcodemsg ExceptionisfileZFIREWALLD_DIRECTr read check_configZ export_configZLOCKDOWN_WHITELISTr ZFIREWALLD_CONFr ) fwrZreadersrZ_dirfileobjerrorrr&/usr/lib/python3.6/functions.pyr!&sz   &. ($ ($  (r!)rZfirewallrZfirewall.errorsrZfirewall.core.fw_configrZfirewall.core.io.zonerZfirewall.core.io.servicerZfirewall.core.io.ipsetrZfirewall.core.io.icmptyperZfirewall.core.io.helperr Zfirewall.core.io.policyr Zfirewall.core.io.directr Z#firewall.core.io.lockdown_whitelistr Zfirewall.core.io.firewalld_confr r!r&r&r&r's            PKpge[r))$io/__pycache__/helper.cpython-36.pycnu[3 g @sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)Helper helper_reader helper_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudp)log)errors) FirewallErrorcseZdZddddddd gffZdZd d gZd d dgd Zd ddgddgdZfddZddZ ddZ ddZ ddZ Z S)!rversionshort descriptionfamilymoduleportsz (sssssa(ss))-.N)rrhelpernameportprotocol)rrcs6tt|jd|_d|_d|_d|_d|_g|_dS)Nr) superr__init__rrrrrr)self) __class__/usr/lib/python3.6/helper.pyr;szHelper.__init__cCs.d|_d|_d|_d|_d|_|jdd=dS)Nr)rrrrrr)rr!r!r"cleanupDs zHelper.cleanupcCsRt|j|_t|j|_t|j|_t|j|_t|j|_dd|jD|_dS)z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSs g|]\}}t|t|fqSr!)r).0ZpoZprr!r!r" Usz)Helper.encode_strings..N)rrrrrrr)rr!r!r"encode_stringsLs      zHelper.encode_stringscCs(ddg}||kr$ttjd||fdS)NZipv4Zipv6z'%s' not in '%s')rrZ INVALID_IPV)rZipvZipvsr!r!r" check_ipvWszHelper.check_ipvcCsz|dkr0xl|D]}t|dt|dqWnF|dkrv|jdsRttjd|t|jdddkrvttjd|dS) Nrrr nf_conntrack_z('%s' does not start with 'nf_conntrack_'rzModule name '%s' too short)r r startswithrrINVALID_MODULElenreplace)rritemZ all_configrr!r!r" _check_config]s    zHelper._check_config)rr)rr)rr)rr)rr)rr)__name__ __module__ __qualname__ZIMPORT_EXPORT_STRUCTUREZDBUS_SIGNATUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSrr#r&r'r/ __classcell__r!r!)r r"r&s$     c@seZdZddZdS)helper_ContentHandlercCs>tj||||jj|||dkrd|kr8|d|j_d|kr\|jj|d|d|j_d|kr|djdstt j d|dt |dj dddkrtt j d |d|d|j_ nz|d krnp|d krnf|d kr:t|d t|d |d |d f}||jjkr$|jjj|ntjd|d |d dS)Nrrrrr)z('%s' does not start with 'nf_conntrack_'rr(zModule name '%s' too shortrrrrz#Port '%s/%s' already set, ignoring.)r startElementr.Zparser_check_element_attrsrr'rr*rrr+r,r-rr r rappendr Zwarning)rrattrsentryr!r!r"r5ns>      z"helper_ContentHandler.startElementN)r0r1r2r5r!r!r!r"r4msr4c Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid helper file: %s)rendswithrrZ INVALID_NAMErZ check_namefilenamepathr*r ETC_FIREWALLDZbuiltindefaultr4saxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_HELPERZ getExceptionrr&) r=r>rhandlerparserrfsourcemsgr!r!r"rs8        (c CsP|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|j|d <|jr|jd kr|j|d <|jr<|jd kr<|j|d <|jd ||jd|jr|jd kr|jd|jdi|j|j|jd|jd|jr|jd kr|jd|jdi|j|j|jd|jdx>|jD]4} |jd|jd| d| dd|jdqW|jd |jd|j|j~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrrrr z rrrrr()rr) r>r=rosexistsshutilZcopy2 Exceptionr errordirnamer*rr?mkdiriorBr Z startDocumentrrrr5ZignorableWhitespacerZ charactersZ endElementrrZ simpleElementZ endDocumentclose) rr>_pathrrHdirpathrFrDr7rr!r!r"rs\                       )N)__all__Zxml.saxrArLrSrNZfirewallrZfirewall.functionsrZfirewall.core.io.io_objectrrr r r r Zfirewall.core.loggerr rZfirewall.errorsrrr4rrr!r!r!r"s        G#PKpge[Wun +io/__pycache__/service.cpython-36.opt-1.pycnu[3 g2@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZmZmZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)Serviceservice_readerservice_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol check_address)log)errors) FirewallErrorc seZdZd d!d"dd#gfddgfdddifddgfd d$gfd dgfd dgff Zd d gZddddZddgddgdgdgddgddgdgdgdZfddZddZddZ ddZ Z S)%rversionshort descriptionportsmodules destination protocols source_portsincludeshelpers_-N)rrservicenameportprotocolvalueipv4ipv6r)rr!r"modulerz source-portincludehelpercsNtt|jd|_d|_d|_g|_g|_g|_i|_ g|_ g|_ g|_ dS)Nr) superr__init__rrrrrrrrrr)self) __class__/usr/lib/python3.6/service.pyr*DszService.__init__cCshd|_d|_d|_|jdd=|jdd=|jdd=|jj|jdd=|j dd=|j dd=dS)Nr) rrrrrrrclearrrr)r+r-r-r.cleanupQs      zService.cleanupcCst|j|_t|j|_t|j|_dd|jD|_dd|jD|_dd|jjD|_dd|jD|_dd|j D|_ dd|j D|_ d d|j D|_ d S) z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSs g|]\}}t|t|fqSr-)r).0poprr-r-r. dsz*Service.encode_strings..cSsg|] }t|qSr-)r)r1mr-r-r.r4escSsi|]\}}t|t|qSr-)r)r1kvr-r-r. fsz*Service.encode_strings..cSsg|] }t|qSr-)r)r1r3r-r-r.r4gscSs g|]\}}t|t|fqSr-)r)r1r2r3r-r-r.r4hscSsg|] }t|qSr-)r)r1sr-r-r.r4jscSsg|] }t|qSr-)r)r1r9r-r-r.r4ksN) rrrrrrritemsrrrr)r+r-r-r.encode_strings]s    zService.encode_stringscCs:|dkrJx>|D]6}|ddkr8t|dt|dqt|dqWn|dkrjx|D] }t|qXWn|dkrx|D]}t|dt|dqxWn|dkrx|D]*}|dkrttjd |t|||qWn^|d kr6xR|D]J}|jd r|jd d}d |kr|jd d}t |dkrttj |qWdS)Nrrrrrrr$r%z'%s' not in {'ipv4'|'ipv6'}r nf_conntrack_rr)r$r%) r r r rrZINVALID_DESTINATIONr startswithreplacelenZINVALID_MODULE)r+ritemZ all_configr!protorr&r-r-r. _check_configms8              zService._check_config)rr)rr)rr)rr)rr) __name__ __module__ __qualname__ZIMPORT_EXPORT_STRUCTUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSr*r0r;rD __classcell__r-r-)r,r.r&s4     c@seZdZddZdS)service_ContentHandlercCs0tj||||jj|||dkrTd|krxRdD]J}||krt|||||jjkr&tjd|n|||jj|<qWn|dkr|d}|jdr~|jdd}d|kr~|jdd}||jjkr|jjj |n tjd|n|dkr|d|jjkr|jjj |dntjd|dn@|dkr,|d|jjkr|jjj |dntjd|ddS)Nrr z'Ignoring deprecated attribute name='%s'rrrr!rr"z#Port '%s/%s' already set, ignoring.z$Protocol '%s' already set, ignoring.r#z source-portz)SourcePort '%s/%s' already set, ignoring.rr$r%z2Destination address for '%s' already set, ignoringr&r=rrz"Module '%s' already set, ignoring.r'z#Include '%s' already set, ignoring.r(z"Helper '%s' already set, ignoring.)r$r%)r startElementrBZparser_check_element_attrsrZwarningrr r rappendr rrrrr?r@rrr)r+r attrsentryxr&r-r-r.rJs                       z#service_ContentHandler.startElementN)rErFrGrJr-r-r-r.rIsrIc Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid service file: %s)rendswithrrZ INVALID_NAMEr Z check_namefilenamepathr?r ETC_FIREWALLDZbuiltindefaultrIsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_SERVICEZ getExceptionrr;) rSrTrhandlerparserr fsourcemsgr-r-r.rs8        (cCsr|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jd ||jd |jrt|jd krt|jd |jdi|j|j|jd|jd |jr|jd kr|jd |jdi|j|j|jd|jd x>|jD]4} |jd |jd| d| dd|jd qWx4|jD]*} |jd |jdd| i|jd qWx>|jD]4} |jd |jd| d| dd|jd qs    (   mQPKpge[E-22(io/__pycache__/zone.cpython-36.opt-1.pycnu[3 gM@sdddgZddljZddlZddlZddlZddlmZddlm Z m Z m Z m Z m Z mZmZddlmZmZddlmZmZmZmZdd lmZmZmZmZdd lmZdd lm Z dd lm!Z!dd l"m#Z#GdddeZ$GdddeZ%dddZ&dddZ'dS)Zone zone_reader zone_writerN)config) checkIPnMask checkIP6nMaskcheckInterfaceuniqifymax_zone_name_len u2b_if_py2 check_mac)DEFAULT_ZONE_TARGET ZONE_TARGETS)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator)common_startElementcommon_endElementcommon_check_config common_writer)rich)log)errors) FirewallErrorcsfeZdZdZd@dAdBdCdDd dgfd dEgfd dgfdFd dGgfddgfddgfddgfddgfddHgfdIdJfZdddgZddddgddgdgdgdddgdgddddgddgddddddgdgddZddddgd gd!d"gd#d$gd%d&d'd#d(gd%d'd(gd)d*gd+gd,gd- Zed.d/Z fd0d1Z d2d3Z d4d5Z fd6d7Z fd8d9Zd:d;Zfdd?ZZS)Krz Zone class versionshort descriptionUNUSEDFtargetservicesports icmp_blocks masquerade forward_ports interfacessources rules_str protocols source_portsicmp_block_inversionforward_-/Nnameportprotocolvalueset)rrzoneservicer1z icmp-blockz icmp-typer,z forward-port interfacerulesource destinationr2z source-portrZauditZacceptrejectZdropZmarklimitzicmp-block-inversion immutableZenabledzto-portzto-addrfamilyZpriorityaddressmacinvertipsetprefixleveltypeZburst) r5r$z forward-portr8r9r:rr;r<cCs8x&ttjD]\}\}}||kr |Sq WttjddS)Nz index_of()) enumeraterIMPORT_EXPORT_STRUCTURErrZ UNKNOWN_ERROR)elementiZelZdummyrJ/usr/lib/python3.6/zone.pyindex_ofdsz Zone.index_ofcstt|jd|_d|_d|_d|_t|_g|_ g|_ g|_ g|_ d|_ d|_g|_g|_g|_g|_d|_g|_g|_d|_d|_d|_dS)NrF)superr__init__rrrrr r r!r"r)r#r,r$r%r*r&r' fw_configrulesr(r+combinedapplied)self) __class__rJrKrNks,z Zone.__init__cCsd|_d|_d|_d|_t|_|jdd=|jdd=|jdd=|j dd=d|_ d|_ |j dd=|j dd=|jdd=|jdd=d|_|jdd=|jdd=d|_d|_d|_dS)NrF)rrrrr r r!r"r)r#r,r$r%r*r&r'rOrPr(r+rQrR)rSrJrJrKcleanups*          z Zone.cleanupcCst|j|_t|j|_t|j|_t|j|_dd|jD|_dd|jD|_dd|jD|_dd|jD|_dd|j D|_ dd|j D|_ dd|j D|_ d d|j D|_ d d|j D|_ d d|jD|_d S) z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSsg|] }t|qSrJ)r ).0srJrJrK sz'Zone.encode_strings..cSs g|]\}}t|t|fqSrJ)r )rVpoprrJrJrKrXscSsg|] }t|qSrJ)r )rVrZrJrJrKrXscSsg|] }t|qSrJ)r )rVrIrJrJrKrXscSs0g|](\}}}}t|t|t|t|fqSrJ)r )rVZp1Zp2Zp3Zp4rJrJrKrXscSs g|]\}}t|t|fqSrJ)r )rVrYrZrJrJrKrXscSsg|] }t|qSrJ)r )rVrIrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXscSsg|] }t|qSrJ)r )rVrWrJrJrKrXsN)r rrrr r!r"r)r#r%r*r&r'rPr()rSrJrJrKencode_stringss     zZone.encode_stringscsN|dkr8dd|D|_tt|j|dd|jDntt|j||dS)Nr(cSsg|]}tj|dqS))Zrule_str)rZ Rich_Rule)rVrWrJrJrKrXsz$Zone.__setattr__..cSsg|] }t|qSrJ)str)rVrWrJrJrKrXs)rPrMr __setattr__)rSr0r3)rTrJrKr]s zZone.__setattr__cstt|j}|d=|S)Nr)rMrexport_config_dict)rSZconf)rTrJrKr^szZone.export_config_dictcCsLt|||||dkr.|tkr*ttj|n|dkrxl|D]d}t|sTttj||jr}||j krq||jj |jkrttjdj ||qWqWdS)Nr r&z)interface '{}' already bound to zone '{}'r'zipset:z&source '{}' already bound to zone '{}')rrrrINVALID_TARGETrZINVALID_INTERFACErOZ get_zonesr0Zget_zoner&formatrrr startswith INVALID_ADDRr')rSritemZ all_configr7r5r9rJrJrK _check_configs6       zZone._check_configcstt|j||jdr,ttjd|n|jdrHttjd|n|jddkrhttjd|nnd|kr|d|j d}n|}t |t krttjd|t |t |j f|j r||j jkrttjddS)Nr/z'%s' can't start with '/'z'%s' can't end with '/'zmore than one '/' in '%s'z'Zone of '%s' has %d chars, max is %d %sz+Zones can't have the same name as a policy.)rMr check_namerarr INVALID_NAMEendswithcountfindlenr rQrOZget_policy_objectsZ NAME_CONFLICT)rSr0Z checked_name)rTrJrKrfs,      zZone.check_namec Csd|_d|_d|_d|_d|_x$|jD]}||jkr&|jj|q&Wx$|jD]}||jkrL|jj|qLWx$|jD]}||jkrr|jj|qrWx$|j D]}||j kr|j j|qWx$|j D]}||j kr|j j|qWx$|j D]}||j kr|j j|qW|j rd|_ |j rd|_ x(|jD]}||jkr&|jj|q&Wx(|jD]}||jkrP|jj|qPWx,|jD]"} |jj| |jjt| qzW|jrd|_dS)NTr)rQfilenamerrrr&appendr'r!r"r)r#r,r$r%r*rPr(r\r+) rSr5r7r9r6r1protoZicmpr,r8rJrJrKcombinesL                  z Zone.combine)rr)rr)rr)rF)r r)rr)r$F)rrrr)rr)r+F)r,F)__name__ __module__ __qualname____doc__rGZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRS staticmethodrLrNrUr[r]r^rdrfro __classcell__rJrJ)rTrKr(sx         c@s$eZdZddZddZddZdS)zone_ContentHandlercCs"tj||d|_d|_d|_dS)NF)rrN_rule _rule_errorZ _limit_ok)rSrcrJrJrKrN s zzone_ContentHandler.__init__c Cstj||||jrdS|jj||t|||r6dS|dkrd|krVtjd|dd|krj|d|j_d|krtjd|dd|kr|d}|t krt t j ||dkr|t kr||j_n|d kr|jjrtjd nd |j_n|d krh|jrtjd d |_dSd|kr.tjdd |_dS|d|jjkrT|jjj|dntjd|dn8|dkrf|jr |jjrtjdt|jd |_dSd}d|kr|djd$krd }d}}}d|kr|d}d|kr|d}d|kr|d}tj||||d|j_dSd|krBd|krBtjddSd|krdd|krdtjddSd|kr~tjd|dd|krtjddSd|krt|d rt|d rt|d rt t j|dd|kr$d|d}||jjkr|jjj|ntjd |dd|kr|d}||jjkrT|jjj|ntjd |dn:|d!kr|jjrtjd"nd |j_ntjd#|dSdS)%Nr5r0z'Ignoring deprecated attribute name='%s'rr=z,Ignoring deprecated attribute immutable='%s'r rr,zForward already set, ignoring.Tr7z$Invalid rule: interface use in rule.z Invalid interface: Name missing.z%Interface '%s' already set, ignoring.r9z:Invalid rule: More than one source in rule '%s', ignoring.FrAyestruer?r@rB)rAz$Invalid source: No address no ipset.z"Invalid source: Address and ipset.r>z)Ignoring deprecated attribute family='%s'z+Invalid source: Invertion not allowed here.zipset:%sz"Source '%s' already set, ignoring.zicmp-block-inversionz+Icmp-Block-Inversion already set, ignoring.zUnknown XML element '%s')ryrz)r startElementrxrcZparser_check_element_attrsrrZwarningrrrrr_r r r,rwr&rmr9r\lowerrZ Rich_Sourcerrr rbr'r+) rSr0attrsr rAZaddrr@rBentryrJrJrKr{&s                                       z zone_ContentHandler.startElementcCstj||t||dS)N)r endElementr)rSr0rJrJrKrs zzone_ContentHandler.endElementN)rprqrrrNr{rrJrJrJrKrvsprvFc Cst}|jds ttjd||dd |_|s>|j|j||_||_|j t j rZdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r} zttjd| jWYdd} ~ XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid zone file: %s)rrhrrrgr0rfrlpathrar ETC_FIREWALLDZbuiltindefaultrvsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZ INVALID_ZONEZ getExceptionrr[) rlrZ no_check_namer5handlerparserr0fr9msgrJrJrKrs:        (c Cs\|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jtkr*|j|d <|jd ||jd t||x8t|jD]*} |jd|jdd| i|jd qVWx\t|jD]N} |jdd| kr|jdd| ddin|jdd| i|jd qW|jr |jd|jdi|jd |jr2|jd|jdi|jd |jd |jd |j |j!~dS)Nz%s/%sz %s/%s.xmlz%s.oldzBackup of file '%s' failed: %siZwtzUTF-8)modeencodingrrr r5 z r7r0zipset:r9rBr?zicmp-block-inversionr,)"rrlr0osexistsshutilZcopy2 ExceptionrerrordirnamerarrmkdiriorrZ startDocumentrr r r{ZignorableWhitespacerr r&Z simpleElementr'r+r,rZ endDocumentclose) r5r_pathr0rdirpathrrr}r7r9rJrJrKrs`                     )F)N)(__all__Zxml.saxrrrrZfirewallrZfirewall.functionsrrrr r r r Zfirewall.core.baser rZfirewall.core.io.io_objectrrrrZfirewall.core.io.policyrrrrZ firewall.corerZfirewall.core.loggerrrZfirewall.errorsrrrvrrrJrJrJrKs$   $    x| PKpge[Wun %io/__pycache__/service.cpython-36.pycnu[3 g2@sdddgZddljZddlZddlZddlZddlmZddlm Z ddl m Z m Z m Z mZmZmZmZmZddlmZdd lmZdd lmZGd dde ZGd d d e ZddZdddZdS)Serviceservice_readerservice_writerN)config) u2b_if_py2)PY2 IO_ObjectIO_Object_ContentHandlerIO_Object_XMLGenerator check_port check_tcpudpcheck_protocol check_address)log)errors) FirewallErrorc seZdZd d!d"dd#gfddgfdddifddgfd d$gfd dgfd dgff Zd d gZddddZddgddgdgdgddgddgdgdgdZfddZddZddZ ddZ Z S)%rversionshort descriptionportsmodules destination protocols source_portsincludeshelpers_-N)rrservicenameportprotocolvalueipv4ipv6r)rr!r"modulerz source-portincludehelpercsNtt|jd|_d|_d|_g|_g|_g|_i|_ g|_ g|_ g|_ dS)Nr) superr__init__rrrrrrrrrr)self) __class__/usr/lib/python3.6/service.pyr*DszService.__init__cCshd|_d|_d|_|jdd=|jdd=|jdd=|jj|jdd=|j dd=|j dd=dS)Nr) rrrrrrrclearrrr)r+r-r-r.cleanupQs      zService.cleanupcCst|j|_t|j|_t|j|_dd|jD|_dd|jD|_dd|jjD|_dd|jD|_dd|j D|_ dd|j D|_ d d|j D|_ d S) z HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.cSs g|]\}}t|t|fqSr-)r).0poprr-r-r. dsz*Service.encode_strings..cSsg|] }t|qSr-)r)r1mr-r-r.r4escSsi|]\}}t|t|qSr-)r)r1kvr-r-r. fsz*Service.encode_strings..cSsg|] }t|qSr-)r)r1r3r-r-r.r4gscSs g|]\}}t|t|fqSr-)r)r1r2r3r-r-r.r4hscSsg|] }t|qSr-)r)r1sr-r-r.r4jscSsg|] }t|qSr-)r)r1r9r-r-r.r4ksN) rrrrrrritemsrrrr)r+r-r-r.encode_strings]s    zService.encode_stringscCs:|dkrJx>|D]6}|ddkr8t|dt|dqt|dqWn|dkrjx|D] }t|qXWn|dkrx|D]}t|dt|dqxWn|dkrx|D]*}|dkrttjd |t|||qWn^|d kr6xR|D]J}|jd r|jd d}d |kr|jd d}t |dkrttj |qWdS)Nrrrrrrr$r%z'%s' not in {'ipv4'|'ipv6'}r nf_conntrack_rr)r$r%) r r r rrZINVALID_DESTINATIONr startswithreplacelenZINVALID_MODULE)r+ritemZ all_configr!protorr&r-r-r. _check_configms8              zService._check_config)rr)rr)rr)rr)rr) __name__ __module__ __qualname__ZIMPORT_EXPORT_STRUCTUREZADDITIONAL_ALNUM_CHARSZPARSER_REQUIRED_ELEMENT_ATTRSZPARSER_OPTIONAL_ELEMENT_ATTRSr*r0r;rD __classcell__r-r-)r,r.r&s4     c@seZdZddZdS)service_ContentHandlercCs0tj||||jj|||dkrTd|krxRdD]J}||krt|||||jjkr&tjd|n|||jj|<qWn|dkr|d}|jdr~|jdd}d|kr~|jdd}||jjkr|jjj |n tjd|n|dkr|d|jjkr|jjj |dntjd|dn@|dkr,|d|jjkr|jjj |dntjd|ddS)Nrr z'Ignoring deprecated attribute name='%s'rrrr!rr"z#Port '%s/%s' already set, ignoring.z$Protocol '%s' already set, ignoring.r#z source-portz)SourcePort '%s/%s' already set, ignoring.rr$r%z2Destination address for '%s' already set, ignoringr&r=rrz"Module '%s' already set, ignoring.r'z#Include '%s' already set, ignoring.r(z"Helper '%s' already set, ignoring.)r$r%)r startElementrBZparser_check_element_attrsrZwarningrr r rappendr rrrrr?r@rrr)r+r attrsentryxr&r-r-r.rJs                       z#service_ContentHandler.startElementN)rErFrGrJr-r-r-r.rIsrIc Cst}|jds ttjd||dd |_|j|j||_||_|j t j rVdnd|_ |j |_ t|}tj}|j|d||f}t|db}tjd}|j|y|j|Wn8tjk r}zttjd|jWYdd}~XnXWdQRX~~tr|j|S) Nz.xmlz'%s' is missing .xml suffixFTz%s/%srbznot a valid service file: %s)rendswithrrZ INVALID_NAMEr Z check_namefilenamepathr?r ETC_FIREWALLDZbuiltindefaultrIsaxZ make_parserZsetContentHandleropenZ InputSourceZ setByteStreamparseZSAXParseExceptionZINVALID_SERVICEZ getExceptionrr;) rSrTrhandlerparserr fsourcemsgr-r-r.rs8        (cCsr|r|n|j}|jr$d||jf}nd||jf}tjj|rytj|d|Wn0tk r}ztj d||WYdd}~XnXtjj |}|j t j rtjj| rtjjt j stjt j dtj|dtj|ddd}t|}|ji}|jr|jd kr|j|d <|jd ||jd |jrt|jd krt|jd |jdi|j|j|jd|jd |jr|jd kr|jd |jdi|j|j|jd|jd x>|jD]4} |jd |jd| d| dd|jd qWx4|jD]*} |jd |jdd| i|jd qWx>|jD]4} |jd |jd| d| dd|jd qs    (   mQPKpge[,:<<io/__init__.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2012 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # fix xmlplus to be compatible with the python xml sax parser and python 3 # by adding __contains__ to xml.sax.xmlreader.AttributesImpl import xml if "_xmlplus" in xml.__file__: from xml.sax.xmlreader import AttributesImpl if not hasattr(AttributesImpl, "__contains__"): # this is missing: def __AttributesImpl__contains__(self, name): return name in getattr(self, "_attrs") # add it using the name __contains__ setattr(AttributesImpl, "__contains__", __AttributesImpl__contains__) from xml.sax.saxutils import XMLGenerator if not hasattr(XMLGenerator, "_write"): # this is missing: def __XMLGenerator_write(self, text): getattr(self, "_out").write(text) # add it using the name _write setattr(XMLGenerator, "_write", __XMLGenerator_write) PKpge[/ io/helper.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2011-2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # __all__ = [ "Helper", "helper_reader", "helper_writer" ] import xml.sax as sax import os import io import shutil from firewall import config from firewall.functions import u2b_if_py2 from firewall.core.io.io_object import PY2, IO_Object, \ IO_Object_ContentHandler, IO_Object_XMLGenerator, check_port, \ check_tcpudp from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError class Helper(IO_Object): IMPORT_EXPORT_STRUCTURE = ( ( "version", "" ), # s ( "short", "" ), # s ( "description", "" ), # s ( "family", "", ), # s ( "module", "", ), # s ( "ports", [ ( "", "" ), ], ), # a(ss) ) DBUS_SIGNATURE = '(sssssa(ss))' ADDITIONAL_ALNUM_CHARS = [ "-", "." ] PARSER_REQUIRED_ELEMENT_ATTRS = { "short": None, "description": None, "helper": [ "module" ], } PARSER_OPTIONAL_ELEMENT_ATTRS = { "helper": [ "name", "version", "family" ], "port": [ "port", "protocol" ], } def __init__(self): super(Helper, self).__init__() self.version = "" self.short = "" self.description = "" self.module = "" self.family = "" self.ports = [ ] def cleanup(self): self.version = "" self.short = "" self.description = "" self.module = "" self.family = "" del self.ports[:] def encode_strings(self): """ HACK. I haven't been able to make sax parser return strings encoded (because of python 2) instead of in unicode. Get rid of it once we throw out python 2 support.""" self.version = u2b_if_py2(self.version) self.short = u2b_if_py2(self.short) self.description = u2b_if_py2(self.description) self.module = u2b_if_py2(self.module) self.family = u2b_if_py2(self.family) self.ports = [(u2b_if_py2(po),u2b_if_py2(pr)) for (po,pr) in self.ports] def check_ipv(self, ipv): ipvs = [ 'ipv4', 'ipv6' ] if ipv not in ipvs: raise FirewallError(errors.INVALID_IPV, "'%s' not in '%s'" % (ipv, ipvs)) def _check_config(self, config, item, all_config): if item == "ports": for port in config: check_port(port[0]) check_tcpudp(port[1]) elif item == "module": if not config.startswith("nf_conntrack_"): raise FirewallError( errors.INVALID_MODULE, "'%s' does not start with 'nf_conntrack_'" % config) if len(config.replace("nf_conntrack_", "")) < 1: raise FirewallError(errors.INVALID_MODULE, "Module name '%s' too short" % config) # PARSER class helper_ContentHandler(IO_Object_ContentHandler): def startElement(self, name, attrs): IO_Object_ContentHandler.startElement(self, name, attrs) self.item.parser_check_element_attrs(name, attrs) if name == "helper": if "version" in attrs: self.item.version = attrs["version"] if "family" in attrs: self.item.check_ipv(attrs["family"]) self.item.family = attrs["family"] if "module" in attrs: if not attrs["module"].startswith("nf_conntrack_"): raise FirewallError( errors.INVALID_MODULE, "'%s' does not start with 'nf_conntrack_'" % \ attrs["module"]) if len(attrs["module"].replace("nf_conntrack_", "")) < 1: raise FirewallError( errors.INVALID_MODULE, "Module name '%s' too short" % attrs["module"]) self.item.module = attrs["module"] elif name == "short": pass elif name == "description": pass elif name == "port": check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) entry = (attrs["port"], attrs["protocol"]) if entry not in self.item.ports: self.item.ports.append(entry) else: log.warning("Port '%s/%s' already set, ignoring.", attrs["port"], attrs["protocol"]) def helper_reader(filename, path): helper = Helper() if not filename.endswith(".xml"): raise FirewallError(errors.INVALID_NAME, "'%s' is missing .xml suffix" % filename) helper.name = filename[:-4] helper.check_name(helper.name) helper.filename = filename helper.path = path helper.builtin = False if path.startswith(config.ETC_FIREWALLD) else True helper.default = helper.builtin handler = helper_ContentHandler(helper) parser = sax.make_parser() parser.setContentHandler(handler) name = "%s/%s" % (path, filename) with open(name, "rb") as f: source = sax.InputSource(None) source.setByteStream(f) try: parser.parse(source) except sax.SAXParseException as msg: raise FirewallError(errors.INVALID_HELPER, "not a valid helper file: %s" % \ msg.getException()) del handler del parser if PY2: helper.encode_strings() return helper def helper_writer(helper, path=None): _path = path if path else helper.path if helper.filename: name = "%s/%s" % (_path, helper.filename) else: name = "%s/%s.xml" % (_path, helper.name) if os.path.exists(name): try: shutil.copy2(name, "%s.old" % name) except Exception as msg: log.error("Backup of file '%s' failed: %s", name, msg) dirpath = os.path.dirname(name) if dirpath.startswith(config.ETC_FIREWALLD) and not os.path.exists(dirpath): if not os.path.exists(config.ETC_FIREWALLD): os.mkdir(config.ETC_FIREWALLD, 0o750) os.mkdir(dirpath, 0o750) f = io.open(name, mode='wt', encoding='UTF-8') handler = IO_Object_XMLGenerator(f) handler.startDocument() # start helper element attrs = {} attrs["module"] = helper.module if helper.version and helper.version != "": attrs["version"] = helper.version if helper.family and helper.family != "": attrs["family"] = helper.family handler.startElement("helper", attrs) handler.ignorableWhitespace("\n") # short if helper.short and helper.short != "": handler.ignorableWhitespace(" ") handler.startElement("short", { }) handler.characters(helper.short) handler.endElement("short") handler.ignorableWhitespace("\n") # description if helper.description and helper.description != "": handler.ignorableWhitespace(" ") handler.startElement("description", { }) handler.characters(helper.description) handler.endElement("description") handler.ignorableWhitespace("\n") # ports for port in helper.ports: handler.ignorableWhitespace(" ") handler.simpleElement("port", { "port": port[0], "protocol": port[1] }) handler.ignorableWhitespace("\n") # end helper element handler.endElement('helper') handler.ignorableWhitespace("\n") handler.endDocument() f.close() del handler PKpge[ __init__.pynu[PKpge[E-kofw_transaction.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """Transaction classes for firewalld""" __all__ = [ "FirewallTransaction" ] import traceback from firewall.core.logger import log from firewall import errors from firewall.errors import FirewallError class FirewallTransaction(object): def __init__(self, fw): self.fw = fw self.rules = { } # [ ( backend.name, [ rule,.. ] ),.. ] self.pre_funcs = [ ] # [ (func, args),.. ] self.post_funcs = [ ] # [ (func, args),.. ] self.fail_funcs = [ ] # [ (func, args),.. ] self.modules = [ ] # [ module,.. ] def clear(self): self.rules.clear() del self.pre_funcs[:] del self.post_funcs[:] del self.fail_funcs[:] def add_rule(self, backend, rule): self.rules.setdefault(backend.name, [ ]).append(rule) def add_rules(self, backend, rules): for rule in rules: self.add_rule(backend, rule) def query_rule(self, backend, rule): return backend.name in self.rules and rule in self.rules[backend.name] def remove_rule(self, backend, rule): if backend.name in self.rules and rule in self.rules[backend.name]: self.rules[backend.name].remove(rule) def add_pre(self, func, *args): self.pre_funcs.append((func, args)) def add_post(self, func, *args): self.post_funcs.append((func, args)) def add_fail(self, func, *args): self.fail_funcs.append((func, args)) def add_module(self, module): if module not in self.modules: self.modules.append(module) def remove_module(self, module): if module in self.modules: self.modules.remove(module) def add_modules(self, modules): for module in modules: self.add_module(module) def remove_modules(self, modules): for module in modules: self.remove_module(module) def prepare(self, enable): log.debug4("%s.prepare(%s, %s)" % (type(self), enable, "...")) rules = { } if not enable: # reverse rule order for cleanup for backend_name in self.rules: for rule in reversed(self.rules[backend_name]): rules.setdefault(backend_name, [ ]).append( self.fw.get_backend_by_name(backend_name).reverse_rule(rule)) else: for backend_name in self.rules: rules.setdefault(backend_name, [ ]).extend(self.rules[backend_name]) return rules, self.modules def execute(self, enable): log.debug4("%s.execute(%s)" % (type(self), enable)) rules, modules = self.prepare(enable) # pre self.pre() # stage 1: apply rules error = False errorMsg = "" done = [ ] for backend_name in rules: try: self.fw.rules(backend_name, rules[backend_name]) except Exception as msg: error = True errorMsg = msg log.debug1(traceback.format_exc()) log.error(msg) else: done.append(backend_name) # stage 2: load modules if not error: module_return = self.fw.handle_modules(modules, enable) if module_return: # Debug log about issues loading modules, but don't error. The # modules may be builtin or CONFIG_MODULES=n, in which case # modprobe will fail. Or we may be running inside a container # that doesn't have sufficient privileges. Unfortunately there # is no way for us to know. (status, msg) = module_return if status: log.debug1(msg) # error case: revert rules if error: undo_rules = { } for backend_name in done: undo_rules[backend_name] = [ ] for rule in reversed(rules[backend_name]): undo_rules[backend_name].append( self.fw.get_backend_by_name(backend_name).reverse_rule(rule)) for backend_name in undo_rules: try: self.fw.rules(backend_name, undo_rules[backend_name]) except Exception as msg: log.debug1(traceback.format_exc()) log.error(msg) # call failure functions for (func, args) in self.fail_funcs: try: func(*args) except Exception as msg: log.debug1(traceback.format_exc()) log.error("Calling fail func %s(%s) failed: %s" % \ (func, args, msg)) raise FirewallError(errors.COMMAND_FAILED, errorMsg) # post self.post() def pre(self): log.debug4("%s.pre()" % type(self)) for (func, args) in self.pre_funcs: try: func(*args) except Exception as msg: log.debug1(traceback.format_exc()) log.error("Calling pre func %s(%s) failed: %s" % \ (func, args, msg)) def post(self): log.debug4("%s.post()" % type(self)) for (func, args) in self.post_funcs: try: func(*args) except Exception as msg: log.debug1(traceback.format_exc()) log.error("Calling post func %s(%s) failed: %s" % \ (func, args, msg)) PKpge[Ɵ8C$$ helper.pynu[# -*- coding: utf-8 -*- # # Copyright (C) 2016 Red Hat, Inc. # # Authors: # Thomas Woerner # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # """The helper maxnamelen""" HELPER_MAXNAMELEN = 32 PKpge[$$ ebtables.pynu[PKpge[ $fw_config.pynu[PKpge[vg=V=V =fw_policy.pynu[PKpge[Uе 8fw_icmptype.pynu[PKpge[gg Bfw_service.pynu[PKpge[3 MInftables.pynu[PKpge[4C88rich.pynu[PKpge[*Yfw_nm.pynu[PKpge[\yy Xufw_zone.pynu[PKpge[266 (base.pynu[PKpge[ɶ x0ipXtables.pynu[PKpge[~ j"watcher.pynu[PKpge[OXWW @/fw_direct.pynu[PKpge[  ricmp.pynu[PKpge[^ܪ>y>y Ɠlogger.pynu[PKpge[g= fw.pynu[PKpge[َ:  Wfw_ifcfg.pynu[PKpge[  modules.pynu[PKpge[ Pq2q2ipset.pynu[PKpge[V_P)) efw_helper.pynu[PKpge[D%prog.pynu[PKpge[%% +fw_ipset.pynu[PKpge[:ےII$Q__pycache__/fw_policy.cpython-36.pycnu[PKpge[$* __pycache__/fw_helper.cpython-36.pycnu[PKpge[&2 __pycache__/fw_nm.cpython-36.opt-1.pycnu[PKpge[ Dm &F __pycache__/fw_icmptype.cpython-36.pycnu[PKpge[|}RR"O __pycache__/fw_zone.cpython-36.pycnu[PKpge[K+B __pycache__/fw_service.cpython-36.opt-1.pycnu[PKpge[  __pycache__/fw_nm.cpython-36.pycnu[PKpge[8&#9 __pycache__/nftables.cpython-36.pycnu[PKpge[B' __pycache__/helper.cpython-36.opt-1.pycnu[PKpge[#pqq# __pycache__/__init__.cpython-36.pycnu[PKpge[#pqq)S __pycache__/__init__.cpython-36.opt-1.pycnu[PKpge[G@ @ ( __pycache__/modules.cpython-36.opt-1.pycnu[PKpge[k-N# __pycache__/ebtables.cpython-36.pycnu[PKpge[EL% __pycache__/icmp.cpython-36.opt-1.pycnu[PKpge[qwט22* __pycache__/fw_direct.cpython-36.opt-1.pycnu[PKpge[EL __pycache__/icmp.cpython-36.pycnu[PKpge[x  , __pycache__/fw_policies.cpython-36.opt-1.pycnu[PKpge[_io/policy.pynu[PKpge[(55io/io_object.pynu[PKpge[DžRR io/ipset.pynu[PKpge[Cc=== iio/direct.pynu[PKpge[m io/ifcfg.pynu[PKpge[5io/icmptype.pynu[PKpge[8MM io/zone.pynu[PKpge[mL22 )io/service.pynu[PKpge[L2\io/__pycache__/firewalld_conf.cpython-36.opt-1.pycnu[PKpge[)`/`/'zio/__pycache__/io_object.cpython-36.pycnu[PKpge[͆ RR$mio/__pycache__/policy.cpython-36.pycnu[PKpge[r))*Kio/__pycache__/helper.cpython-36.opt-1.pycnu[PKpge[m&io/__pycache__/__init__.cpython-36.pycnu[PKpge[V..*io/__pycache__/direct.cpython-36.opt-1.pycnu[PKpge[m,Fio/__pycache__/__init__.cpython-36.opt-1.pycnu[PKpge[*;]q 'Iio/__pycache__/functions.cpython-36.pycnu[PKpge[)`/`/-Tio/__pycache__/io_object.cpython-36.opt-1.pycnu[PKpge[{k",}io/__pycache__/icmptype.cpython-36.opt-1.pycnu[PKpge[{k"&vio/__pycache__/icmptype.cpython-36.pycnu[PKpge[>)iio/__pycache__/ifcfg.cpython-36.opt-1.pycnu[PKpge[I}h%h%6io/__pycache__/lockdown_whitelist.cpython-36.opt-1.pycnu[PKpge[E-22"aio/__pycache__/zone.cpython-36.pycnu[PKpge[V..$zio/__pycache__/direct.cpython-36.pycnu[PKpge[L,Dio/__pycache__/firewalld_conf.cpython-36.pycnu[PKpge[͆ RR*kbio/__pycache__/policy.cpython-36.opt-1.pycnu[PKpge[x++)Oio/__pycache__/ipset.cpython-36.opt-1.pycnu[PKpge[x++#4io/__pycache__/ipset.cpython-36.pycnu[PKpge[># io/__pycache__/ifcfg.cpython-36.pycnu[PKpge[I}h%h%07io/__pycache__/lockdown_whitelist.cpython-36.pycnu[PKpge[*;]q -Bio/__pycache__/functions.cpython-36.opt-1.pycnu[PKpge[r))$ Nio/__pycache__/helper.cpython-36.pycnu[PKpge[Wun +eio/__pycache__/service.cpython-36.opt-1.pycnu[PKpge[E-22(io/__pycache__/zone.cpython-36.opt-1.pycnu[PKpge[Wun %io/__pycache__/service.cpython-36.pycnu[PKpge[,:<<Tio/__init__.pynu[PKpge[/ io/helper.pynu[PKpge[ __init__.pynu[PKpge[E-kofw_transaction.pynu[PKpge[Ɵ8C$$ helper.pynu[PKuu*<