Beispiel #1
0
 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)
Beispiel #2
0
def common_check_config(obj, config, item, all_config):
    if item == "services" and obj.fw_config:
        existing_services = obj.fw_config.get_services()
        for service in config:
            if service not in existing_services:
                raise FirewallError(errors.INVALID_SERVICE,
                                    "'%s' not among existing services" % \
                                    service)
    elif item == "ports":
        for port in config:
            check_port(port[0])
            check_tcpudp(port[1])
    elif item == "protocols":
        for proto in config:
            check_protocol(proto)
    elif item == "icmp_blocks" and obj.fw_config:
        existing_icmptypes = obj.fw_config.get_icmptypes()
        for icmptype in config:
            if icmptype not in existing_icmptypes:
                raise FirewallError(errors.INVALID_ICMPTYPE,
                                    "'%s' not among existing icmp types" % \
                                    icmptype)
    elif item == "forward_ports":
        for fwd_port in config:
            check_port(fwd_port[0])
            check_tcpudp(fwd_port[1])
            if not fwd_port[2] and not fwd_port[3]:
                raise FirewallError(
                    errors.INVALID_FORWARD,
                    "'%s' is missing to-port AND to-addr " % fwd_port)
            if fwd_port[2]:
                check_port(fwd_port[2])
            if fwd_port[3]:
                if not checkIP(fwd_port[3]) and not checkIP6(fwd_port[3]):
                    raise FirewallError(
                        errors.INVALID_ADDR,
                        "to-addr '%s' is not a valid address" % fwd_port[3])
    elif item == "source_ports":
        for port in config:
            check_port(port[0])
            check_tcpudp(port[1])
    elif item in ["rules_str", "rich_rules"]:
        for rule in config:
            obj_rich = rich.Rich_Rule(rule_str=rule)
            if obj.fw_config and obj_rich.element and (isinstance(obj_rich.element, rich.Rich_IcmpBlock) or
                                                       isinstance(obj_rich.element, rich.Rich_IcmpType)):
                existing_icmptypes = obj.fw_config.get_icmptypes()
                if obj_rich.element.name not in existing_icmptypes:
                    raise FirewallError(errors.INVALID_ICMPTYPE,
                                        "'%s' not among existing icmp types" % \
                                        obj_rich.element.name)
                elif obj_rich.family:
                    ict = obj.fw_config.get_icmptype(obj_rich.element.name)
                    if ict.destination and obj_rich.family not in ict.destination:
                        raise FirewallError(errors.INVALID_ICMPTYPE,
                                            "rich rule family '%s' conflicts with icmp type '%s'" % \
                                            (obj_rich.family, obj_rich.element.name))
Beispiel #3
0
 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 POLICY_TARGETS:
             raise FirewallError(errors.INVALID_TARGET, config)
     elif item == "rules_str":
         for rule in config:
             rich.Rich_Rule(rule_str=rule)
     elif item in ["ingress-zone", "egress-zone"] and self.fw_config:
         existing_zones = self.fw_config.get_zones()
         for zone in config:
             if zone not in existing_zones:
                 raise FirewallError(errors.INVALID_SERVICE,
                                     "'%s' not among existing zones" % zone)
Beispiel #4
0
    def _check_config(self, config, item, all_config):
        common_check_config(self, config, item, all_config)

        if item == "target":
            if config not in POLICY_TARGETS:
                raise FirewallError(errors.INVALID_TARGET,
                                    "'%s' is invalid target" % (config))
        elif item == "priority":
            if config in self.priority_reserved or \
               config > self.priority_max or \
               config < self.priority_min:
                raise FirewallError(
                    errors.INVALID_PRIORITY,
                    "%d is invalid priority. Must be in range [%d, %d]. The following are reserved: %s"
                    % (config, self.priority_min, self.priority_max,
                       self.priority_reserved))
        elif item in ["ingress_zones", "egress_zones"]:
            existing_zones = ["ANY", "HOST"]
            if self.fw_config:
                existing_zones += self.fw_config.get_zones()
            for zone in config:
                if zone not in existing_zones:
                    raise FirewallError(
                        errors.INVALID_ZONE,
                        "'%s' not among existing zones" % (zone))
                if ((zone not in ["ANY", "HOST"] and (set(["ANY", "HOST"]) & set(config))) or \
                   (zone in ["ANY", "HOST"] and (set(config) - set([zone])))):
                    raise FirewallError(
                        errors.INVALID_ZONE,
                        "'%s' may only contain one of: many regular zones, ANY, or HOST"
                        % (item))
                if zone == "HOST" and \
                   ((item == "ingress_zones" and "egress_zones" in all_config and "HOST" in all_config["egress_zones"]) or \
                   (item == "egress_zones" and "ingress_zones" in all_config and "HOST" in all_config["ingress_zones"])):
                    raise FirewallError(
                        errors.INVALID_ZONE,
                        "'HOST' can only appear in either ingress or egress zones, but not both"
                    )
        elif item == "masquerade" and config:
            if "egress_zones" in all_config and "HOST" in all_config[
                    "egress_zones"]:
                raise FirewallError(
                    errors.INVALID_ZONE,
                    "'masquerade' is invalid for egress zone 'HOST'")
            elif "ingress_zones" in all_config:
                if "HOST" in all_config["ingress_zones"]:
                    raise FirewallError(
                        errors.INVALID_ZONE,
                        "'masquerade' is invalid for ingress zone 'HOST'")
                for zone in all_config["ingress_zones"]:
                    if zone == "ANY":
                        continue
                    z_obj = self.fw_config.get_zone(zone)
                    if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(
                            z_obj):
                        raise FirewallError(
                            errors.INVALID_ZONE,
                            "'masquerade' cannot be used in a policy if an ingress zone has assigned interfaces"
                        )
        elif item == "rich_rules":
            for rule in config:
                obj = rich.Rich_Rule(rule_str=rule)
                if obj.element and isinstance(obj.element,
                                              rich.Rich_Masquerade):
                    if "egress_zones" in all_config and "HOST" in all_config[
                            "egress_zones"]:
                        raise FirewallError(
                            errors.INVALID_ZONE,
                            "'masquerade' is invalid for egress zone 'HOST'")
                    elif "ingress_zones" in all_config:
                        if "HOST" in all_config["ingress_zones"]:
                            raise FirewallError(
                                errors.INVALID_ZONE,
                                "'masquerade' is invalid for ingress zone 'HOST'"
                            )
                        for zone in all_config["ingress_zones"]:
                            if zone == "ANY":
                                continue
                            z_obj = self.fw_config.get_zone(zone)
                            if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(
                                    z_obj):
                                raise FirewallError(
                                    errors.INVALID_ZONE,
                                    "'masquerade' cannot be used in a policy if an ingress zone has assigned interfaces"
                                )
                elif obj.element and isinstance(obj.element,
                                                rich.Rich_ForwardPort):
                    if "egress_zones" in all_config:
                        if "HOST" in all_config["egress_zones"]:
                            if obj.element.to_address:
                                raise FirewallError(
                                    errors.INVALID_FORWARD,
                                    "A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'"
                                )
                        elif all_config["egress_zones"]:
                            if not obj.element.to_address:
                                raise FirewallError(
                                    errors.INVALID_FORWARD,
                                    "'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone"
                                )
                            if "ANY" not in all_config["egress_zones"]:
                                for zone in all_config["egress_zones"]:
                                    z_obj = self.fw_config.get_zone(zone)
                                    if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(
                                            z_obj):
                                        raise FirewallError(
                                            errors.INVALID_ZONE,
                                            "'forward-port' cannot be used in a policy if an egress zone has assigned interfaces"
                                        )
                elif obj.action and isinstance(obj.action, rich.Rich_Mark):
                    if "egress_zones" in all_config:
                        for zone in all_config["egress_zones"]:
                            if zone in ["ANY", "HOST"]:
                                continue
                            z_obj = self.fw_config.get_zone(zone)
                            if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(
                                    z_obj):
                                raise FirewallError(
                                    errors.INVALID_ZONE,
                                    "'mark' action cannot be used in a policy if an egress zone has assigned interfaces"
                                )
        elif item == "forward_ports":
            for fwd_port in config:
                if "ingress_zones" in all_config and "HOST" in all_config[
                        "ingress_zones"]:
                    raise FirewallError(
                        errors.INVALID_ZONE,
                        "'forward-port' is invalid for ingress zone 'HOST'")
                elif "egress_zones" in all_config:
                    if "HOST" in all_config["egress_zones"]:
                        if fwd_port[3]:
                            raise FirewallError(
                                errors.INVALID_FORWARD,
                                "A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'"
                            )
                    elif all_config["egress_zones"]:
                        if not fwd_port[3]:
                            raise FirewallError(
                                errors.INVALID_FORWARD,
                                "'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone"
                            )
                        if "ANY" not in all_config["egress_zones"]:
                            for zone in all_config["egress_zones"]:
                                z_obj = self.fw_config.get_zone(zone)
                                if self.fw_config and "interfaces" in self.fw_config.get_zone_config_dict(
                                        z_obj):
                                    raise FirewallError(
                                        errors.INVALID_ZONE,
                                        "'forward-port' cannot be used in a policy if an egress zone has assigned interfaces"
                                    )
Beispiel #5
0
def common_startElement(obj, name, attrs):
    if name == "short":
        pass
    elif name == "description":
        pass

    elif name == "service":
        if obj._rule:
            if obj._rule.element:
                log.warning(
                    "Invalid rule: More than one element in rule '%s', ignoring.",
                    str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_Service(attrs["name"])
            return True
        if attrs["name"] not in obj.item.services:
            obj.item.services.append(attrs["name"])
        else:
            log.warning("Service '%s' already set, ignoring.", attrs["name"])

    elif name == "port":
        if obj._rule:
            if obj._rule.element:
                log.warning(
                    "Invalid rule: More than one element in rule '%s', ignoring.",
                    str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_Port(attrs["port"],
                                               attrs["protocol"])
            return True
        check_port(attrs["port"])
        check_tcpudp(attrs["protocol"])
        entry = (portStr(attrs["port"], "-"), attrs["protocol"])
        if entry not in obj.item.ports:
            obj.item.ports.append(entry)
        else:
            log.warning("Port '%s/%s' already set, ignoring.", attrs["port"],
                        attrs["protocol"])

    elif name == "protocol":
        if obj._rule:
            if obj._rule.element:
                log.warning(
                    "Invalid rule: More than one element in rule '%s', ignoring.",
                    str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_Protocol(attrs["value"])
        else:
            check_protocol(attrs["value"])
            if attrs["value"] not in obj.item.protocols:
                obj.item.protocols.append(attrs["value"])
            else:
                log.warning("Protocol '%s' already set, ignoring.",
                            attrs["value"])

    elif name == "tcp-mss-clamp":
        if obj._rule:
            if obj._rule.element:
                log.warning(
                    "Invalid rule: More than one element in rule '%s', ignoring.",
                    str(obj._rule))
                obj._rule_error = True
                return True
            _value = "pmtu"
            if "value" in attrs:
                _value = attrs["value"]
            obj._rule.element = rich.Rich_Tcp_Mss_Clamp(_value)
        else:
            log.warning("Invalid rule: tcp-mss-clamp '%s' outside of rule",
                        attrs["value"])

    elif name == "icmp-block":
        if obj._rule:
            if obj._rule.element:
                log.warning(
                    "Invalid rule: More than one element in rule '%s', ignoring.",
                    str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_IcmpBlock(attrs["name"])
            return True
        if attrs["name"] not in obj.item.icmp_blocks:
            obj.item.icmp_blocks.append(attrs["name"])
        else:
            log.warning("icmp-block '%s' already set, ignoring.",
                        attrs["name"])

    elif name == "icmp-type":
        if obj._rule:
            if obj._rule.element:
                log.warning(
                    "Invalid rule: More than one element in rule '%s', ignoring.",
                    str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_IcmpType(attrs["name"])
            return True
        else:
            log.warning("Invalid rule: icmp-block '%s' outside of rule",
                        attrs["name"])

    elif name == "masquerade":
        if obj._rule:
            if obj._rule.element:
                log.warning(
                    "Invalid rule: More than one element in rule '%s', ignoring.",
                    str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_Masquerade()
        else:
            if obj.item.masquerade:
                log.warning("Masquerade already set, ignoring.")
            else:
                obj.item.masquerade = True

    elif name == "forward-port":
        to_port = ""
        if "to-port" in attrs:
            to_port = attrs["to-port"]
        to_addr = ""
        if "to-addr" in attrs:
            to_addr = attrs["to-addr"]

        if obj._rule:
            if obj._rule.element:
                log.warning(
                    "Invalid rule: More than one element in rule '%s', ignoring.",
                    str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_ForwardPort(attrs["port"],
                                                      attrs["protocol"],
                                                      to_port, to_addr)
            return True

        check_port(attrs["port"])
        check_tcpudp(attrs["protocol"])
        if to_port:
            check_port(to_port)
        if to_addr:
            if not checkIP(to_addr) and not checkIP6(to_addr):
                raise FirewallError(errors.INVALID_ADDR,
                                    "to-addr '%s' is not a valid address" \
                                    % to_addr)
        entry = (portStr(attrs["port"],
                         "-"), attrs["protocol"], portStr(to_port,
                                                          "-"), str(to_addr))
        if entry not in obj.item.forward_ports:
            obj.item.forward_ports.append(entry)
        else:
            log.warning("Forward port %s/%s%s%s already set, ignoring.",
                        attrs["port"], attrs["protocol"],
                        " >%s" % to_port if to_port else "",
                        " @%s" % to_addr if to_addr else "")

    elif name == "source-port":
        if obj._rule:
            if obj._rule.element:
                log.warning(
                    "Invalid rule: More than one element in rule '%s', ignoring.",
                    str(obj._rule))
                obj._rule_error = True
                return True
            obj._rule.element = rich.Rich_SourcePort(attrs["port"],
                                                     attrs["protocol"])
            return True
        check_port(attrs["port"])
        check_tcpudp(attrs["protocol"])
        entry = (portStr(attrs["port"], "-"), attrs["protocol"])
        if entry not in obj.item.source_ports:
            obj.item.source_ports.append(entry)
        else:
            log.warning("Source port '%s/%s' already set, ignoring.",
                        attrs["port"], attrs["protocol"])

    elif name == "destination":
        if not obj._rule:
            log.warning('Invalid rule: Destination outside of rule')
            obj._rule_error = True
            return True
        if obj._rule.destination:
            log.warning(
                "Invalid rule: More than one destination in rule '%s', ignoring.",
                str(obj._rule))
            return True
        invert = False
        address = None
        if "address" in attrs:
            address = attrs["address"]
        ipset = None
        if "ipset" in attrs:
            ipset = attrs["ipset"]
        if "invert" in attrs and \
                attrs["invert"].lower() in [ "yes", "true" ]:
            invert = True
        obj._rule.destination = rich.Rich_Destination(address, ipset, invert)

    elif name in ["accept", "reject", "drop", "mark"]:
        if not obj._rule:
            log.warning('Invalid rule: Action outside of rule')
            obj._rule_error = True
            return True
        if obj._rule.action:
            log.warning('Invalid rule: More than one action')
            obj._rule_error = True
            return True
        if name == "accept":
            obj._rule.action = rich.Rich_Accept()
        elif name == "reject":
            _type = None
            if "type" in attrs:
                _type = attrs["type"]
            obj._rule.action = rich.Rich_Reject(_type)
        elif name == "drop":
            obj._rule.action = rich.Rich_Drop()
        elif name == "mark":
            _set = attrs["set"]
            obj._rule.action = rich.Rich_Mark(_set)
        obj._limit_ok = obj._rule.action

    elif name == "log":
        if not obj._rule:
            log.warning('Invalid rule: Log outside of rule')
            return True
        if obj._rule.log:
            log.warning('Invalid rule: More than one log')
            return True
        level = None
        if "level" in attrs:
            level = attrs["level"]
            if level not in [
                    "emerg", "alert", "crit", "error", "warning", "notice",
                    "info", "debug"
            ]:
                log.warning('Invalid rule: Invalid log level')
                obj._rule_error = True
                return True
        prefix = None
        if "prefix" in attrs:
            prefix = attrs["prefix"]
            if not prefix or len(prefix) > 127:
                log.warning('Invalid rule: Invalid log prefix')
                obj._rule_error = True
                return True
        obj._rule.log = rich.Rich_Log(prefix, level)
        obj._limit_ok = obj._rule.log

    elif name == "nflog":
        if not obj._rule:
            log.warning('Invalid rule: Log outside of rule')
            return True
        if obj._rule.log:
            log.warning('Invalid rule: More than one log')
            return True
        group = None
        if "group" in attrs:
            group = attrs["group"]
            if not checkUINT16(group):
                log.warning('Invalid rule: Invalid nflog group value')
                obj._rule_error = True
                return True
        prefix = None
        if "prefix" in attrs:
            prefix = attrs["prefix"]
            if not prefix or len(prefix) > 127:
                log.warning('Invalid rule: Invalid nflog prefix')
                obj._rule_error = True
                return True
        threshold = None
        if "queue-size" in attrs:
            threshold = attrs["queue-size"]
            if not checkUINT16(threshold):
                log.warning('Invalid rule: Invalid nflog queue-size')
                obj._rule_error = True
                return True
        obj._rule.log = rich.Rich_NFLog(group, prefix, threshold)
        obj._limit_ok = obj._rule.log

    elif name == "audit":
        if not obj._rule:
            log.warning('Invalid rule: Audit outside of rule')
            return True
        if obj._rule.audit:
            log.warning(
                "Invalid rule: More than one audit in rule '%s', ignoring.",
                str(obj._rule))
            obj._rule_error = True
            return True
        obj._rule.audit = rich.Rich_Audit()
        obj._limit_ok = obj._rule.audit

    elif name == "rule":
        family = None
        priority = 0
        if "family" in attrs:
            family = attrs["family"]
            if family not in ["ipv4", "ipv6"]:
                log.warning('Invalid rule: Rule family "%s" invalid',
                            attrs["family"])
                obj._rule_error = True
                return True
        if "priority" in attrs:
            priority = int(attrs["priority"])
        obj._rule = rich.Rich_Rule(family=family, priority=priority)

    elif name == "limit":
        if not obj._limit_ok:
            log.warning('Invalid rule: Limit outside of action, log and audit')
            obj._rule_error = True
            return True
        if obj._limit_ok.limit:
            log.warning(
                "Invalid rule: More than one limit in rule '%s', ignoring.",
                str(obj._rule))
            obj._rule_error = True
            return True
        value = attrs["value"]
        obj._limit_ok.limit = rich.Rich_Limit(value)
    else:
        return False

    return True
Beispiel #6
0
    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
Beispiel #7
0
 def __setattr__(self, name, value):
     if name == "rules_str":
         self.rules = [rich.Rich_Rule(rule_str=s) for s in value]
     else:
         super(Zone, self).__setattr__(name, value)
Beispiel #8
0
    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["zones"]:
            raise FirewallError(errors.NAME_CONFLICT, "Policy '{}': Can't have the same name as a zone.".format(self.name))

        if item == "target":
            if config not in POLICY_TARGETS:
                raise FirewallError(errors.INVALID_TARGET, "Policy '{}': '{}' is invalid target".format(self.name, config))
        elif item == "priority":
            if config in self.priority_reserved or \
               config > self.priority_max or \
               config < self.priority_min:
                raise FirewallError(errors.INVALID_PRIORITY,
                        "Policy '{}': {} is invalid priority. Must be in range [{}, {}]. The following are reserved: {}".format(
                            self.name, config, self.priority_min, self.priority_max, self.priority_reserved))
        elif item in ["ingress_zones", "egress_zones"]:
            existing_zones = ["ANY", "HOST"] + list(all_io_objects["zones"].keys())
            for zone in config:
                if zone not in existing_zones:
                    raise FirewallError(errors.INVALID_ZONE,
                            "Policy '{}': '{}' not among existing zones".format(
                                self.name, zone))
                if ((zone not in ["ANY", "HOST"] and (set(["ANY", "HOST"]) & set(config))) or \
                   (zone in ["ANY", "HOST"] and (set(config) - set([zone])))):
                    raise FirewallError(errors.INVALID_ZONE,
                            "Policy '{}': '{}' may only contain one of: many regular zones, ANY, or HOST".format(
                                self.name, item))
                if zone == "HOST" and \
                   ((item == "ingress_zones" and "egress_zones" in all_config and "HOST" in all_config["egress_zones"]) or \
                   (item == "egress_zones" and "ingress_zones" in all_config and "HOST" in all_config["ingress_zones"])):
                    raise FirewallError(errors.INVALID_ZONE,
                            "Policy '{}': 'HOST' can only appear in either ingress or egress zones, but not both".format(
                                self.name))
        elif item == "masquerade" and config:
            if "egress_zones" in all_config and "HOST" in all_config["egress_zones"]:
                raise FirewallError(errors.INVALID_ZONE,
                    "Policy '{}': 'masquerade' is invalid for egress zone 'HOST'".format(
                        self.name))
            elif "ingress_zones" in all_config:
                if "HOST" in all_config["ingress_zones"]:
                    raise FirewallError(errors.INVALID_ZONE,
                            "Policy '{}': 'masquerade' is invalid for ingress zone 'HOST'".format(
                                self.name))
                for zone in all_config["ingress_zones"]:
                    if zone == "ANY":
                        continue
                    if zone not in all_io_objects["zones"]:
                        raise FirewallError(errors.INVALID_ZONE, "Policy '{}': Zone '{}' does not exist.".format(self.name, zone))
                    if all_io_objects["zones"][zone].interfaces:
                        raise FirewallError(errors.INVALID_ZONE, "Policy '{}': 'masquerade' cannot be used because ingress zone '{}' has assigned interfaces. ".format(self.name, zone))
        elif item == "rich_rules":
            for rule in config:
                obj = rich.Rich_Rule(rule_str=rule)
                if obj.element and isinstance(obj.element, rich.Rich_Masquerade):
                    if "egress_zones" in all_config and "HOST" in all_config["egress_zones"]:
                        raise FirewallError(errors.INVALID_ZONE,
                                "Policy '{}': 'masquerade' is invalid for egress zone 'HOST'".format(
                                    self.name))
                    elif "ingress_zones" in all_config:
                        if "HOST" in all_config["ingress_zones"]:
                            raise FirewallError(errors.INVALID_ZONE,
                                    "Policy '{}': 'masquerade' is invalid for ingress zone 'HOST'".format(
                                        self.name))
                        for zone in all_config["ingress_zones"]:
                            if zone == "ANY":
                                continue
                            if zone not in all_io_objects["zones"]:
                                raise FirewallError(errors.INVALID_ZONE, "Policy '{}': Zone '{}' does not exist.".format(self.name, zone))
                            if all_io_objects["zones"][zone].interfaces:
                                raise FirewallError(errors.INVALID_ZONE, "Policy '{}': 'masquerade' cannot be used because ingress zone '{}' has assigned interfaces. ".format(self.name, zone))
                elif obj.element and isinstance(obj.element, rich.Rich_ForwardPort):
                    if "egress_zones" in all_config:
                        if "HOST" in all_config["egress_zones"]:
                            if obj.element.to_address:
                                raise FirewallError(errors.INVALID_FORWARD,
                                        "Policy '{}': A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'".format(
                                            self.name))
                        elif all_config["egress_zones"]:
                            if not obj.element.to_address:
                                raise FirewallError(errors.INVALID_FORWARD,
                                        "Policy '{}': 'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone".format(
                                            self.name))
                            if "ANY" not in all_config["egress_zones"]:
                                for zone in all_config["egress_zones"]:
                                    if zone not in all_io_objects["zones"]:
                                        raise FirewallError(errors.INVALID_ZONE, "Policy '{}': Zone '{}' does not exist.".format(self.name, zone))
                                    if all_io_objects["zones"][zone].interfaces:
                                        raise FirewallError(errors.INVALID_ZONE, "Policy '{}': 'forward-port' cannot be used because egress zone '{}' has assigned interfaces".format(self.name, zone))
                elif obj.action and isinstance(obj.action, rich.Rich_Mark):
                    if "egress_zones" in all_config:
                        for zone in all_config["egress_zones"]:
                            if zone in ["ANY", "HOST"]:
                                continue
                            if zone not in all_io_objects["zones"]:
                                raise FirewallError(errors.INVALID_ZONE, "Policy '{}': Zone '{}' does not exist.".format(self.name, zone))
                            if all_io_objects["zones"][zone].interfaces:
                                raise FirewallError(errors.INVALID_ZONE, "Policy '{}': 'mark' action cannot be used because egress zone '{}' has assigned interfaces".format(self.name, zone))
        elif item == "forward_ports":
            for fwd_port in config:
                if "egress_zones" in all_config:
                    if "HOST" in all_config["egress_zones"]:
                        if fwd_port[3]:
                            raise FirewallError(errors.INVALID_FORWARD,
                                    "Policy '{}': A 'forward-port' with 'to-addr' is invalid for egress zone 'HOST'".format(
                                        self.name))
                    elif all_config["egress_zones"]:
                        if not fwd_port[3]:
                            raise FirewallError(errors.INVALID_FORWARD,
                                    "Policy '{}': 'forward-port' requires 'to-addr' if egress zone is 'ANY' or a zone".format(
                                        self.name))
                        if "ANY" not in all_config["egress_zones"]:
                            for zone in all_config["egress_zones"]:
                                if zone not in all_io_objects["zones"]:
                                    raise FirewallError(errors.INVALID_ZONE, "Policy '{}': Zone '{}' does not exist.".format(self.name, zone))
                                if all_io_objects["zones"][zone].interfaces:
                                    raise FirewallError(errors.INVALID_ZONE, "Policy '{}': 'forward-port' cannot be used because egress zone '{}' has assigned interfaces".format(self.name, zone))
Beispiel #9
0
def common_check_config(obj, config, item, all_config, all_io_objects):
    obj_type = "Policy" if isinstance(obj, Policy) else "Zone"

    if item == "services" and "services" in all_io_objects:
        existing_services = all_io_objects["services"]
        for service in config:
            if service not in existing_services:
                raise FirewallError(errors.INVALID_SERVICE,
                        "{} '{}': '{}' not among existing services".format(
                            obj_type, obj.name, 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 "icmptypes" in all_io_objects:
        existing_icmptypes = all_io_objects["icmptypes"]
        for icmptype in config:
            if icmptype not in existing_icmptypes:
                ex = FirewallError(errors.INVALID_ICMPTYPE,
                        "{} '{}': '{}' not among existing ICMP types".format(
                            obj_type, obj.name, icmptype))
                if icmptype in all_io_objects.get("icmptypes_unsupported", {}):
                    log.debug1("{} (unsupported)".format(ex))
                else:
                    raise ex

    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,
                    "{} '{}': '{}' is missing to-port AND to-addr ".format(
                        obj_type, obj.name, 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 '{}' is not a valid address".format(
                            obj_type, obj.name, fwd_port[3]))
    elif item == "source_ports":
        for port in config:
            check_port(port[0])
            check_tcpudp(port[1])
    elif item in ["rules_str", "rich_rules"]:
        for rule in config:
            obj_rich = rich.Rich_Rule(rule_str=rule)
            if obj_rich.element and "icmptypes" in all_io_objects and \
              (isinstance(obj_rich.element, rich.Rich_IcmpBlock) or
               isinstance(obj_rich.element, rich.Rich_IcmpType)):
                existing_icmptypes = all_io_objects["icmptypes"]
                if obj_rich.element.name not in existing_icmptypes:
                    ex = FirewallError(errors.INVALID_ICMPTYPE,
                            "{} '{}': '{}' not among existing ICMP types".format(
                                obj_type, obj.name, obj_rich.element.name))
                    if obj_rich.element.name in all_io_objects.get("icmptypes_unsupported", {}):
                        log.debug1("{} (unsupported)".format(ex))
                    else:
                        raise ex
                elif obj_rich.family:
                    ict = all_io_objects["icmptypes"][obj_rich.element.name]
                    if ict.destination and obj_rich.family not in ict.destination:
                        ex = FirewallError(errors.INVALID_ICMPTYPE,
                                           "{} '{}': rich rule family '{}' conflicts with icmp type '{}'".format(
                                           obj_type, obj.name, obj_rich.family, obj_rich.element.name))
                        ict_unsupported = all_io_objects.get("icmptypes_unsupported", {}).get(obj_rich.element.name)
                        if ict_unsupported and ict_unsupported.destination and \
                           obj_rich.family in ict_unsupported.destination:
                            log.debug1("{} (unsupported)".format(ex))
                        else:
                            raise ex
Beispiel #10
0
    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 == "policy":
            if "version" in attrs:
                self.item.version = attrs["version"]
            if "priority" in attrs:
                self.item.priority = int(attrs["priority"])
            target = attrs["target"]
            if target not in POLICY_TARGETS:
                raise FirewallError(errors.INVALID_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 == "ingress-zone":
            if attrs["name"] not in self.item.ingress_zones:
                self.item.ingress_zones.append(attrs["name"])
            else:
                log.warning("Ingress zone '%s' already set, ignoring.",
                            attrs["name"])
        elif name == "egress-zone":
            if attrs["name"] not in self.item.egress_zones:
                self.item.egress_zones.append(attrs["name"])
            else:
                log.warning("Egress zone '%s' already set, ignoring.",
                            attrs["name"])

        elif name == "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 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 == "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
            priority = 0
            if "family" in attrs:
                family = attrs["family"]
                if family not in ["ipv4", "ipv6"]:
                    log.warning('Invalid rule: Rule family "%s" invalid',
                                attrs["family"])
                    self._rule_error = True
                    return
            if "priority" in attrs:
                priority = int(attrs["priority"])
            self._rule = rich.Rich_Rule(family=family, priority=priority)

        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)

        else:
            log.warning("Unknown XML element '%s'", name)
            return