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 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( INVALID_ENTRY, "entry '%s' does not match ipset type '%s'" % (entry, ipset_type) ) for split in splits: if (family == "ipv4" and not checkIP(entry)) or (family == "ipv6" and not checkIP6(entry)): raise FirewallError( 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( 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(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(INVALID_ENTRY, "entry '%s' does not match ipset type '%s'" % (entry, ipset_type)) else: raise FirewallError(INVALID_IPSET, "ipset type '%s' not usable" % ipset_type)
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 parse_source(self, value): if not checkIPnMask(value) and not checkIP6nMask(value) \ and not check_mac(value) and not \ (value.startswith("ipset:") and len(value) > 6): raise FirewallError(errors.INVALID_ADDR, "'%s' is no valid IPv4, IPv6 or MAC address, nor an ipset" % value) return value
def _check_config(self, config, item): if item == "services" and self.fw_config: existing_services = self.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 self.fw_config: existing_icmptypes = self.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 == "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) 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) elif item == "rules_str": for rule in config: rich.Rich_Rule(rule_str=rule)
def _check_config(self, config, item): if item == "services" and self.fw_config: existing_services = self.fw_config.get_services() for service in config: if not service 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 self.fw_config: existing_icmptypes = self.fw_config.get_icmptypes() for icmptype in config: if not icmptype 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]): 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 == "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) 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) elif item == "rules_str": for rule in config: Rich_Rule(rule_str=rule)
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 build_zone_source_address_rules(self, enable, zone, zone_target, address, table, chain): add_del = {True: "-A", False: "-D"}[enable] opt = { "PREROUTING": "-s", "POSTROUTING": "-d", "INPUT": "-s", "FORWARD_IN": "-s", "FORWARD_OUT": "-d", "OUTPUT": "-d", }[chain] target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) if zone_target == DEFAULT_ZONE_TARGET: action = "-g" else: action = "-j" if address.startswith("ipset:"): name = address[6:] if opt == "-d": opt = "dst" else: opt = "src" flags = ",".join([opt] * self._fw.ipset.get_dimension(name)) rule = [ add_del, "%s_ZONES_SOURCE" % chain, "-t", table, "-m", "set", "--match-set", name, flags, action, target ] else: if check_mac(address): # outgoing can not be set if opt == "-d": return "" rule = [ add_del, "%s_ZONES_SOURCE" % chain, "-t", table, "-m", "mac", "--mac-source", address.upper(), action, target ] else: rule = [ add_del, "%s_ZONES_SOURCE" % chain, "-t", table, opt, address, action, target ] return [rule]
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) 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)
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 _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 build_zone_source_address(self, enable, zone, zone_target, address, table, chain): add_del = { True: "-A", False: "-D" }[enable] opt = { "PREROUTING": "-s", "POSTROUTING": "-d", "INPUT": "-s", "FORWARD_IN": "-s", "FORWARD_OUT": "-d", "OUTPUT": "-d", }[chain] target = DEFAULT_ZONE_TARGET.format(chain=SHORTCUTS[chain], zone=zone) if zone_target == DEFAULT_ZONE_TARGET: action = "-g" else: action = "-j" if address.startswith("ipset:"): name = address[6:] if opt == "-d": opt = "dst" else: opt = "src" flags = ",".join([opt] * self._fw.ipset.get_dimension(name)) rule = [ add_del, "%s_ZONES_SOURCE" % chain, "-t", table, "-m", "set", "--match-set", name, flags, action, target ] else: if check_mac(address): # outgoing can not be set if opt == "-d": return "" rule = [ add_del, "%s_ZONES_SOURCE" % chain, "-t", table, "-m", "mac", "--mac-source", address.upper(), action, target ] else: rule = [ add_del, "%s_ZONES_SOURCE" % chain, "-t", table, opt, address, action, target ] return rule
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 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 and self.destination is None: 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.family is None: raise FirewallError(errors.INVALID_FAMILY) if self.destination.addr is not None and self.destination.ipset is not None raise FirewallError(errors.INVALID_RULE, "address and ipset") if self.destination.ipset is None: 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)) else: if not check_ipset_name(self.destination.ipset): raise FirewallError(errors.INVALID_IPSET, str(self.destination.ipset)) # 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")
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_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(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, Rich_Tcp_Mss_Clamp ]: 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) # tcp-mss-clamp elif type(self.element) == Rich_Tcp_Mss_Clamp: if self.action is not None: raise FirewallError( errors.INVALID_RULE, "tcp-mss-clamp and %s are mutually exclusive" % self.action) if self.element.value: if not functions.checkTcpMssClamp(self.element.value): raise FirewallError(errors.INVALID_RULE, self.element.value) # 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: self.log.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 query_source(self, zone, source): if check_mac(source): source = source.upper() return self.__source_id(source) in self.get_zone(zone).sources
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 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 == "short": pass elif name == "description": pass elif name == "service": if self._rule: if self._rule.element: log.warning( "Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_Service(attrs["name"]) return if attrs["name"] not in self.item.services: self.item.services.append(attrs["name"]) else: log.warning("Service '%s' already set, ignoring.", attrs["name"]) elif name == "port": if self._rule: if self._rule.element: log.warning( "Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_Port(attrs["port"], attrs["protocol"]) return check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) entry = (portStr(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"]) elif name == "protocol": if self._rule: if self._rule.element: log.warning( "Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_Protocol(attrs["value"]) else: 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 == "icmp-block": if self._rule: if self._rule.element: log.warning( "Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_IcmpBlock(attrs["name"]) return if attrs["name"] not in self.item.icmp_blocks: self.item.icmp_blocks.append(attrs["name"]) else: log.warning("icmp-block '%s' already set, ignoring.", attrs["name"]) elif name == "icmp-type": if self._rule: if self._rule.element: log.warning( "Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_IcmpType(attrs["name"]) return else: log.warning("Invalid rule: icmp-block '%s' outside of rule", attrs["name"]) elif name == "masquerade": if "enabled" in attrs and \ attrs["enabled"].lower() in [ "no", "false" ] : log.warning("Ignoring deprecated attribute enabled='%s'", attrs["enabled"]) return if self._rule: if self._rule.element: log.warning( "Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_Masquerade() else: if self.item.masquerade: log.warning("Masquerade already set, ignoring.") else: self.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 self._rule: if self._rule.element: log.warning( "Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_ForwardPort( attrs["port"], attrs["protocol"], to_port, to_addr) return 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 self.item.forward_ports: self.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 self._rule: if self._rule.element: log.warning( "Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = rich.Rich_SourcePort( attrs["port"], attrs["protocol"]) return check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) entry = (portStr(attrs["port"], "-"), attrs["protocol"]) if entry not in self.item.source_ports: self.item.source_ports.append(entry) else: log.warning("Source port '%s/%s' already set, ignoring.", attrs["port"], attrs["protocol"]) 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 == "destination": if not self._rule: log.warning('Invalid rule: Destination outside of rule') self._rule_error = True return if self._rule.destination: log.warning( "Invalid rule: More than one destination in rule '%s', ignoring.", str(self._rule)) return invert = False if "invert" in attrs and \ attrs["invert"].lower() in [ "yes", "true" ]: invert = True self._rule.destination = rich.Rich_Destination( attrs["address"], invert) elif name in ["accept", "reject", "drop", "mark"]: if not self._rule: log.warning('Invalid rule: Action outside of rule') self._rule_error = True return if self._rule.action: log.warning('Invalid rule: More than one action') self._rule_error = True return if name == "accept": self._rule.action = rich.Rich_Accept() elif name == "reject": _type = None if "type" in attrs: _type = attrs["type"] self._rule.action = rich.Rich_Reject(_type) elif name == "drop": self._rule.action = rich.Rich_Drop() elif name == "mark": _set = attrs["set"] self._rule.action = rich.Rich_Mark(_set) self._limit_ok = self._rule.action elif name == "log": if not self._rule: log.warning('Invalid rule: Log outside of rule') return if self._rule.log: log.warning('Invalid rule: More than one log') return 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') self._rule_error = True return prefix = attrs["prefix"] if "prefix" in attrs else None self._rule.log = rich.Rich_Log(prefix, level) self._limit_ok = self._rule.log elif name == "audit": if not self._rule: log.warning('Invalid rule: Audit outside of rule') return if self._rule.audit: log.warning( "Invalid rule: More than one audit in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.audit = rich.Rich_Audit() self._limit_ok = self._rule.audit elif name == "rule": family = None if "family" in attrs: family = attrs["family"] if family not in ["ipv4", "ipv6"]: log.warning('Invalid rule: Rule family "%s" invalid', attrs["family"]) self._rule_error = True return self._rule = rich.Rich_Rule(family) elif name == "limit": if not self._limit_ok: log.warning( 'Invalid rule: Limit outside of action, log and audit') self._rule_error = True return if self._limit_ok.limit: log.warning( "Invalid rule: More than one limit in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return value = attrs["value"] self._limit_ok.limit = rich.Rich_Limit(value) 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 check(self): if self.family is not None and self.family not in [ "ipv4", "ipv6" ]: raise FirewallError(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(MISSING_FAMILY) if type(self.element) == Rich_ForwardPort: raise FirewallError(MISSING_FAMILY) if self.element is None: if self.action is None: raise FirewallError(INVALID_RULE, "no element, no action") if self.source is None: raise FirewallError(INVALID_RULE, "no element, no source") if self.destination is not None: raise FirewallError(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(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(INVALID_FAMILY) if self.source.mac is not None: raise FirewallError(INVALID_RULE, "address and mac") if not functions.check_address(self.family, self.source.addr): raise FirewallError(INVALID_ADDR, str(self.source.addr)) elif self.source.mac is not None: if not functions.check_mac(self.source.mac): raise FirewallError(INVALID_MAC, str(self.source.mac)) elif self.source.ipset is not None: if not functions.check_ipset(self.source.ipset): raise FirewallError(INVALID_IPSET, str(self.source.ipset)) else: raise FirewallError(INVALID_RULE, "invalid source") # destination if self.destination is not None: if self.family is None: raise FirewallError(INVALID_FAMILY) if self.destination.addr is None or \ not functions.check_address(self.family, self.destination.addr): raise FirewallError(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(INVALID_SERVICE, str(self.element.name)) # port elif type(self.element) == Rich_Port: if not functions.check_port(self.element.port): raise FirewallError(INVALID_PORT, self.element.port) if self.element.protocol not in [ "tcp", "udp" ]: raise FirewallError(INVALID_PROTOCOL, self.element.protocol) # protocol elif type(self.element) == Rich_Protocol: if not functions.checkProtocol(self.element.value): raise FirewallError(INVALID_PROTOCOL, self.element.value) # masquerade elif type(self.element) == Rich_Masquerade: if self.action is not None: raise FirewallError(INVALID_RULE, "masquerade and action") if self.source is not None and self.source.mac is not None: raise FirewallError(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(INVALID_ICMPTYPE, str(self.element.name)) if self.action: raise FirewallError(INVALID_RULE, "icmp-block and action") # forward-port elif type(self.element) == Rich_ForwardPort: if not functions.check_port(self.element.port): raise FirewallError(INVALID_PORT, self.element.port) if self.element.protocol not in [ "tcp", "udp" ]: raise FirewallError(INVALID_PROTOCOL, self.element.protocol) if self.element.to_port == "" and self.element.to_address == "": raise FirewallError(INVALID_PORT, self.element.to_port) if self.element.to_port != "" and \ not functions.check_port(self.element.to_port): raise FirewallError(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(INVALID_ADDR, self.element.to_address) if self.family is None: raise FirewallError(INVALID_FAMILY) if self.action is not None: raise FirewallError(INVALID_RULE, "forward-port and action") # other element and not empty? elif self.element is not None: raise FirewallError(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(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(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) if self.action.limit is not None: self.action.limit.check()
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 query_source(self, zone, source): if check_mac(source): source = source.upper() return self.__source_id(source) in self.get_settings(zone)["sources"]
def startElement(self, name, attrs): IO_Object_ContentHandler.startElement(self, name) if self._rule_error: return self.item.parser_check_element_attrs(name, attrs) if 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(INVALID_TARGET, target) if target != "" and target != DEFAULT_ZONE_TARGET: self.item.target = target elif name == "short": pass elif name == "description": pass elif name == "service": if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = Rich_Service(attrs["name"]) return if attrs["name"] not in self.item.services: self.item.services.append(attrs["name"]) else: log.warning("Service '%s' already set, ignoring.", attrs["name"]) elif name == "port": if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = Rich_Port(attrs["port"], attrs["protocol"]) return check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) entry = (portStr(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"]) elif name == "protocol": if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = Rich_Protocol(attrs["value"]) else: 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 == "icmp-block": if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = Rich_IcmpBlock(attrs["name"]) return if attrs["name"] not in self.item.icmp_blocks: self.item.icmp_blocks.append(attrs["name"]) else: log.warning("icmp-block '%s' already set, ignoring.", attrs["name"]) elif name == "masquerade": if "enabled" in attrs: log.warning("Ignoring deprecated attribute enabled='%s'", attrs["enabled"]) if self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = Rich_Masquerade() else: if self.item.masquerade: log.warning("Masquerade already set, ignoring.") else: self.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 self._rule: if self._rule.element: log.warning("Invalid rule: More than one element in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.element = Rich_ForwardPort(attrs["port"], attrs["protocol"], to_port, to_addr) return check_port(attrs["port"]) check_tcpudp(attrs["protocol"]) if to_port: check_port(to_port) if to_addr: if not checkIP(to_addr): raise FirewallError(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 self.item.forward_ports: self.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 == "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 attrs["name"] 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_Source(addr, mac, ipset, invert=invert) return # zone bound to source if "address" not in attrs and not "ipset" 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(INVALID_ADDR, source) 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 == "destination": if not self._rule: log.warning('Invalid rule: Destination outside of rule') self._rule_error = True return if self._rule.destination: log.warning("Invalid rule: More than one destination in rule '%s', ignoring.", str(self._rule)) return invert = False if "invert" in attrs and \ attrs["invert"].lower() in [ "yes", "true" ]: invert = True self._rule.destination = Rich_Destination(attrs["address"], invert) elif name in [ "accept", "reject", "drop", "mark" ]: if not self._rule: log.warning('Invalid rule: Action outside of rule') self._rule_error = True return if self._rule.action: log.warning('Invalid rule: More than one action') self._rule_error = True return if name == "accept": self._rule.action = Rich_Accept() elif name == "reject": _type = None if "type" in attrs: _type = attrs["type"] self._rule.action = Rich_Reject(_type) elif name == "drop": self._rule.action = Rich_Drop() elif name == "mark": _set = attrs["set"] self._rule.action = Rich_Mark(_set) self._limit_ok = self._rule.action elif name == "log": if not self._rule: log.warning('Invalid rule: Log outside of rule') return if self._rule.log: log.warning('Invalid rule: More than one log') return 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') self._rule_error = True return prefix = attrs["prefix"] if "prefix" in attrs else None self._rule.log = Rich_Log(prefix, level) self._limit_ok = self._rule.log elif name == "audit": if not self._rule: log.warning('Invalid rule: Audit outside of rule') return if self._rule.audit: log.warning("Invalid rule: More than one audit in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return self._rule.audit = Rich_Audit() self._limit_ok = self._rule.audit elif name == "rule": family = None if "family" in attrs: family = attrs["family"] if family not in [ "ipv4", "ipv6" ]: log.warning('Invalid rule: Rule family "%s" invalid', attrs["family"]) self._rule_error = True return self._rule = Rich_Rule(family) elif name == "limit": if not self._limit_ok: log.warning('Invalid rule: Limit outside of action, log and audit') self._rule_error = True return if self._limit_ok.limit: log.warning("Invalid rule: More than one limit in rule '%s', ignoring.", str(self._rule)) self._rule_error = True return value = attrs["value"] self._limit_ok.limit = Rich_Limit(value) else: log.warning("Unknown XML element '%s'", name) return