def __cmd_sequence(self, cmd_type, option, action_method, query_method, parse_method, message, start_args=None, end_args=None, no_exit=False): if self.fw is not None: self.fw.authorizeAll() items = [ ] _errors = 0 for item in option: if parse_method is not None: try: item = parse_method(item) except Exception as msg: if len(option) > 1: self.print_warning("Warning: %s" % msg) _errors += 1 continue else: code = FirewallError.get_code(str(msg)) self.print_and_exit("Error: %s" % msg, code) _errors += 1 items.append(item) for item in items: call_item = [ ] if start_args is not None: call_item += start_args if not isinstance(item, list) and not isinstance(item, tuple): call_item.append(item) else: call_item += item if end_args is not None: call_item += end_args self.deactivate_exception_handler() try: action_method(*call_item) except DBusException as msg: code = FirewallError.get_code(msg.get_dbus_message()) if len(option) > 1: self.print_warning("Warning: %s" % msg.get_dbus_message()) else: self.print_and_exit("Error: %s" % msg.get_dbus_message(), code) _errors += 1 except Exception as msg: if len(option) > 1: self.print_warning("Warning: %s" % msg) _errors += 1 continue else: code = FirewallError.get_code(str(msg)) self.print_and_exit("Error: %s" % msg, code) _errors += 1 self.activate_exception_handler() if _errors == len(option) and not no_exit: sys.exit(errors.UNKNOWN_ERROR)
def __query_sequence(self, option, query_method, parse_method, message, # pylint: disable=R0913 start_args=None, no_exit=False): items = [ ] for item in option: if parse_method is not None: try: item = parse_method(item) except Exception as msg: if len(option) > 1: self.print_warning("Warning: %s" % msg) continue else: code = FirewallError.get_code(str(msg)) self.print_and_exit("Error: %s" % msg, code) items.append(item) for item in items: call_item = [ ] if start_args is not None: call_item += start_args if not isinstance(item, list) and not isinstance(item, tuple): call_item.append(item) else: call_item += item self.deactivate_exception_handler() try: res = query_method(*call_item) except DBusException as msg: self.fail_if_not_authorized(msg.get_dbus_name()) code = FirewallError.get_code(msg.get_dbus_message()) if len(option) > 1: self.print_warning("Warning: %s" % msg.get_dbus_message()) continue else: self.print_and_exit("Error: %s" % msg.get_dbus_message(), code) except Exception as msg: code = FirewallError.get_code(str(msg)) if len(option) > 1: self.print_warning("Warning: %s" % msg) else: self.print_and_exit("Error: %s" % msg, code) self.activate_exception_handler() if len(option) > 1: self.print_msg("%s: %s" % (message % item, ("no", "yes")[res])) else: self.print_query_result(res) if not no_exit: sys.exit(0)
def __query_sequence(self, option, query_method, parse_method, message, start_args=[]): items = [ ] for item in option: if parse_method != None: items.append(parse_method(item)) else: items.append(item) for item in items: call_item = start_args[:] if not isinstance(item, list) and not isinstance(item, tuple): call_item.append(item) else: call_item += item try: res = query_method(*call_item) except DBusException as msg: code = FirewallError.get_code(msg) if len(option) > 1: self.print_warning("Warning: %s" % msg.get_dbus_message()) else: self.print_and_exit("Error: %s" % msg.get_dbus_message(), code) continue if len(option) > 1: self.print_msg("%s: %s" % (message % item, ("no", "yes")[res])) else: self.print_query_result(res) sys.exit(0)
def exception_handler(self, exception_message): if not self.__use_exception_handler: raise self.fail_if_not_authorized(exception_message) code = FirewallError.get_code(str(exception_message)) if code in [ errors.ALREADY_ENABLED, errors.NOT_ENABLED, errors.ZONE_ALREADY_SET, errors.ALREADY_SET ]: self.print_warning("Warning: %s" % exception_message) else: self.print_and_exit("Error: %s" % exception_message, code)
def exception_handler(self, exception_message): if "NotAuthorizedException" in exception_message: msg = """Authorization failed. Make sure polkit agent is running or run the application as superuser.""" self.print_and_exit(msg, errors.NOT_AUTHORIZED) else: code = FirewallError.get_code(exception_message) if code in [ errors.ALREADY_ENABLED, errors.NOT_ENABLED, errors.ZONE_ALREADY_SET ]: self.print_warning("Warning: %s" % exception_message) else: self.print_and_exit("Error: %s" % exception_message, code)
def addSourcePort(self, port, protocol, sender=None): port = dbus_to_python(port, str) protocol = dbus_to_python(protocol, str) log.debug1("%s.addSourcePort('%s', '%s')", self._log_prefix, port, protocol) self.parent.accessCheck(sender) settings = list(self.getSettings()) existing_port_ids = list( filter(lambda x: x[1] == protocol, settings[14])) for port_id in existing_port_ids: if portInPortRange(port, port_id[0]): raise FirewallError(errors.ALREADY_ENABLED, "%s:%s" % (port, protocol)) added_ranges, removed_ranges = coalescePortRange( port, [_port for (_port, _protocol) in existing_port_ids]) for range in removed_ranges: settings[14].remove((portStr(range, "-"), protocol)) for range in added_ranges: settings[14].append((portStr(range, "-"), protocol)) self.update(settings)
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 _impl(*args, **kwargs): try: return func(*args, **kwargs) except FirewallError as error: code = FirewallError.get_code(str(error)) if code in [ errors.ALREADY_ENABLED, errors.NOT_ENABLED, errors.ZONE_ALREADY_SET, errors.ALREADY_SET ]: log.warning(str(error)) else: log.debug1(traceback.format_exc()) log.error(str(error)) raise FirewallDBusException(str(error)) except DBusException as ex: # only log DBusExceptions once raise ex except Exception as ex: log.exception() raise FirewallDBusException(str(ex))
def parse_forward_port(self, value): port = None protocol = None toport = None toaddr = None args = value.split(":") for arg in args: try: (opt, val) = arg.split("=") if opt == "port": port = val elif opt == "proto": protocol = val elif opt == "toport": toport = val elif opt == "toaddr": toaddr = val except ValueError: raise FirewallError(errors.INVALID_FORWARD, "invalid forward port arg '%s'" % (arg)) if not port: raise FirewallError(errors.INVALID_FORWARD, "missing port") if not protocol: raise FirewallError(errors.INVALID_FORWARD, "missing protocol") if not (toport or toaddr): raise FirewallError(errors.INVALID_FORWARD, "missing destination") if not check_port(port): raise FirewallError(errors.INVALID_PORT, port) if protocol not in [ "tcp", "udp", "sctp", "dccp" ]: raise FirewallError(errors.INVALID_PROTOCOL, "'%s' not in {'tcp'|'udp'|'sctp'|'dccp'}" % \ protocol) if toport and not check_port(toport): raise FirewallError(errors.INVALID_PORT, toport) if toaddr and not check_single_address("ipv4", toaddr): raise FirewallError(errors.INVALID_ADDR, toaddr) return (port, protocol, toport, toaddr)
def dbus_handle_exceptions(func, *args, **kwargs): """Decorator to handle exceptions, log and report them into D-Bus :Raises DBusException: on a firewall error code problems. """ try: return func(*args, **kwargs) except FirewallError as error: code = FirewallError.get_code(str(error)) if code in [ errors.ALREADY_ENABLED, errors.NOT_ENABLED, errors.ZONE_ALREADY_SET, errors.ALREADY_SET ]: log.warning(str(error)) else: log.error(str(error)) raise FirewallDBusException(str(error)) except DBusException as ex: # only log DBusExceptions once raise ex except Exception as ex: log.exception() raise FirewallDBusException(str(ex))
def new_service(self, name, conf): try: self.get_service(name) except: pass else: raise FirewallError(errors.NAME_CONFLICT, "new_service(): '%s'" % name) x = Service() x.check_name(name) x.import_config(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 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(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, "r") as f: parser.parse(f) del handler del parser if PY2: icmptype.encode_strings() return icmptype
def reverse_passthrough(self, 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(errors.INVALID_PASSTHROUGH, "no '-A', '-I' or '-N' arg")
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 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 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(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, "r") as f: parser.parse(f) del handler del parser if PY2: service.encode_strings() return service
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 rules(self, ipv, rules): _rules = rules[:] backend = self.get_ipv_backend(ipv) if not backend: raise FirewallError(errors.INVALID_IPV, "'%s' is not a valid backend" % ipv) if not self.is_ipv_enabled(ipv): return "" if self._individual_calls or \ not backend.restore_command_exists or \ (ipv == "eb" and not self.ebtables_backend.restore_noflush_option): for i,rule in enumerate(_rules): # remove leading and trailing '"' for use with execve j = 0 while j < len(rule): x = rule[j] if len(x) > 2 and x[0] == '"' and x[-1] == '"': rule[j] = x[1:-1] j += 1 try: backend.set_rule(rule) except Exception as msg: log.error("Failed to apply rules. A firewall reload might solve the issue if the firewall has been modified using ip*tables or ebtables.") log.error(msg) for rule in reversed(_rules[:i]): try: backend.set_rule(backend.reverse_rule(rule)) except Exception: # ignore errors here pass return False return True else: return backend.set_rules(_rules, log_denied=self._log_denied)
def _check_config(self, config, item, all_config, all_io_objects): common_check_config(self, config, item, all_config, all_io_objects) if self.name in all_io_objects["policies"]: raise FirewallError( errors.NAME_CONFLICT, "Zone '{}': Can't have the same name as a policy.".format( self.name)) if item == "target": if config not in ZONE_TARGETS: raise FirewallError( errors.INVALID_TARGET, "Zone '{}': invalid target '{}'".format(self.name, config)) elif item == "interfaces": for interface in config: if not checkInterface(interface): raise FirewallError( errors.INVALID_INTERFACE, "Zone '{}': invalid interface '{}'".format( self.name, interface)) for zone in all_io_objects["zones"]: if zone == self.name: continue if interface in all_io_objects["zones"][zone].interfaces: raise FirewallError( errors.INVALID_INTERFACE, "Zone '{}': interface '{}' already bound to zone '{}'" .format(self.name, 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, "Zone '{}': invalid source '{}'".format( self.name, source)) for zone in all_io_objects["zones"]: if zone == self.name: continue if source in all_io_objects["zones"][zone].sources: raise FirewallError( errors.INVALID_ADDR, "Zone '{}': source '{}' already bound to zone '{}'" .format(self.name, source, zone))
def check_entry(entry, options, ipset_type): family = "ipv4" if "family" in options: if options["family"] == "inet6": family = "ipv6" if ipset_type == "hash:ip": if "-" in entry: splits = entry.split("-") if len(splits) != 2: raise FirewallError( errors.INVALID_ENTRY, "entry '%s' does not match ipset type '%s'" % \ (entry, ipset_type)) for split in splits: if (family == "ipv4" and not checkIP(split)) or \ (family == "ipv6" and not checkIP6(split)): raise FirewallError( errors.INVALID_ENTRY, "entry '%s' does not match ipset type '%s'" % \ (entry, ipset_type)) else: if (family == "ipv4" and not checkIPnMask(entry)) or \ (family == "ipv6" and not checkIP6nMask(entry)): raise FirewallError( errors.INVALID_ENTRY, "entry '%s' does not match ipset type '%s'" % \ (entry, ipset_type)) elif ipset_type == "hash:net": if (family == "ipv4" and not checkIPnMask(entry)) or \ (family == "ipv6" and not checkIP6nMask(entry)): raise FirewallError( errors.INVALID_ENTRY, "entry '%s' does not match ipset type '%s'" % \ (entry, ipset_type)) elif ipset_type == "hash:mac": # ipset does not allow to add 00:00:00:00:00:00 if not check_mac(entry) or entry == "00:00:00:00:00:00": raise FirewallError( errors.INVALID_ENTRY, "entry '%s' does not match ipset type '%s'" % \ (entry, ipset_type)) else: raise FirewallError(errors.INVALID_IPSET, "ipset type '%s' not usable" % ipset_type)
def remove_forward(self, zone, use_transaction=None): _zone = self._fw.check_zone(zone) self._fw.check_panic() _obj = self._zones[_zone] if not _obj.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) if use_transaction is None: transaction.execute(True) return _zone
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(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, "r") as f: parser.parse(f) del handler del parser if "timeout" in ipset.options 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 while i < len(ipset.entries): 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: i += 1 if PY2: ipset.encode_strings() return ipset
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.element is None: if self.action is None: raise FirewallError(errors.INVALID_RULE, "no element, no action") if self.source is None: raise FirewallError(errors.INVALID_RULE, "no element, no source") if self.destination is not None: raise FirewallError(errors.INVALID_RULE, "destination action") 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 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 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.family is None: raise FirewallError(errors.INVALID_FAMILY) if self.destination.addr is None or \ not functions.check_address(self.family, self.destination.addr): raise FirewallError(errors.INVALID_ADDR, str(self.destination.addr)) # 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"]: 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") # 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"]: 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") # 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 check_icmptype(self, icmptype): if icmptype not in self._icmptypes: raise FirewallError(errors.INVALID_ICMPTYPE, icmptype)
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 _import_from_string(self, rule_str): if not rule_str: raise FirewallError(errors.INVALID_RULE, 'empty rule') 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 [ 'family', 'address', 'mac', 'ipset', 'invert', 'value', 'port', 'protocol', 'to-port', 'to-addr', 'name', 'prefix', 'level', 'type', 'set' ]: raise FirewallError(errors.INVALID_RULE, "bad attribute '%s'" % attr_name) else: # element if element in [ 'rule', 'source', 'destination', 'protocol', 'service', 'port', 'icmp-block', 'masquerade', 'forward-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', 'masquerade', 'forward-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=...'.") else: raise FirewallError( errors.INVALID_RULE, "'%s' outside of any element. Use 'rule <element> %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: 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 <element> %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')) in_elements.pop() # source attrs.clear() index = index - 1 # return token to input elif in_element == 'destination': if attr_name in ['address', 'invert']: attrs[attr_name] = attr_value elif element in ['not', 'NOT']: attrs['invert'] = True else: self.destination = Rich_Destination( attrs.get('address'), attrs.get('invert')) 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 == '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 == '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 == 'value': attrs['limit'] = Rich_Limit(attr_value) in_elements.pop() # limit else: raise FirewallError(errors.INVALID_RULE, "invalid 'limit' element") index = index + 1 self.check()
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 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 check_ipset(self, name): if name not in self.get_ipsets(): raise FirewallError(errors.INVALID_IPSET, name)
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 check_ip(self, ip): if not functions.checkIP(ip): raise FirewallError(errors.INVALID_ADDR, ip)
def check_applied_obj(self, obj): if not obj.applied: raise FirewallError(errors.NOT_APPLIED, obj.name)
def check_port(self, port): if not functions.check_port(port): raise FirewallError(errors.INVALID_PORT, port)
def check_interface(self, interface): if not functions.checkInterface(interface): raise FirewallError(errors.INVALID_INTERFACE, interface)
def check_panic(self): if self._panic: raise FirewallError(errors.PANIC_MODE)
def __cmd_sequence(self, cmd_type, option, action_method, query_method, # pylint: disable=W0613, R0913, R0914 parse_method, message, start_args=None, end_args=None, # pylint: disable=W0613 no_exit=False): if self.fw is not None: self.fw.authorizeAll() items = [ ] _errors = 0 _error_codes = [ ] for item in option: if parse_method is not None: try: item = parse_method(item) except Exception as msg: code = FirewallError.get_code(str(msg)) if len(option) > 1: self.print_warning("Warning: %s" % msg) else: self.print_and_exit("Error: %s" % msg, code) if code not in _error_codes: _error_codes.append(code) _errors += 1 continue items.append(item) for item in items: call_item = [ ] if start_args is not None: call_item += start_args if not isinstance(item, list) and not isinstance(item, tuple): call_item.append(item) else: call_item += item if end_args is not None: call_item += end_args self.deactivate_exception_handler() try: action_method(*call_item) except (DBusException, Exception) as msg: if isinstance(msg, DBusException): self.fail_if_not_authorized(msg.get_dbus_name()) msg = msg.get_dbus_message() else: msg = str(msg) code = FirewallError.get_code(msg) if code in [ errors.ALREADY_ENABLED, errors.NOT_ENABLED, errors.ZONE_ALREADY_SET, errors.ALREADY_SET ]: code = 0 if len(option) > 1: self.print_warning("Warning: %s" % msg) elif code == 0: self.print_warning("Warning: %s" % msg) return else: self.print_and_exit("Error: %s" % msg, code) if code not in _error_codes: _error_codes.append(code) _errors += 1 self.activate_exception_handler() if not no_exit: if len(option) > _errors or 0 in _error_codes: # There have been more options than errors or there # was at least one error code 0, return. return elif len(_error_codes) == 1: # Exactly one error code, use it. sys.exit(_error_codes[0]) elif len(_error_codes) > 1: # There is more than error, exit using # UNKNOWN_ERROR. This could happen within sequences # where parsing failed with different errors like # INVALID_PORT and INVALID_PROTOCOL. sys.exit(errors.UNKNOWN_ERROR)
def __cmd_sequence(self, cmd_type, option, action_method, query_method, parse_method, message, start_args=None, end_args=None, no_exit=False): warn_type = { "add": "ALREADY_ENABLED", "remove": "NOT_ENABLED", } items = [ ] _errors = 0 for item in option: if parse_method is not None: try: item = parse_method(item) except Exception as msg: if len(option) > 1: self.print_warning("Warning: %s" % msg) continue else: code = FirewallError.get_code(msg) self.print_and_exit("Error: %s" % msg, code) call_item = [ ] if start_args is not None: call_item += start_args if not isinstance(item, list) and not isinstance(item, tuple): call_item.append(item) else: call_item += item self.deactivate_exception_handler() try: if cmd_type == "add" and not query_method(*call_item): items.append(item) elif cmd_type == "remove" and query_method(*call_item): items.append(item) else: if len(option) > 1: self.print_warning("Warning: %s: %s" % \ (warn_type[cmd_type], message % item)) else: code = FirewallError.get_code(warn_type[cmd_type]) self.print_and_exit("Error: %s: %s" % \ (warn_type[cmd_type], message % item), code) _errors += 1 except DBusException as msg: code = FirewallError.get_code(msg) if len(option) > 1: self.print_warning("Warning: %s" % msg.get_dbus_message()) continue else: self.print_and_exit("Error: %s" % msg.get_dbus_message(), code) _errors += 1 self.activate_exception_handler() for item in items: call_item = [ ] if start_args is not None: call_item += start_args if not isinstance(item, list) and not isinstance(item, tuple): call_item.append(item) else: call_item += item if end_args is not None: call_item += end_args try: action_method(*call_item) except DBusException as msg: code = FirewallError.get_code(msg) if len(option) > 1: self.print_warning("Warning: %s" % msg.get_dbus_message()) else: self.print_and_exit("Error: %s" % msg.get_dbus_message(), code) _errors += 1 if _errors == len(option) and not no_exit: sys.exit(0)