Example #1
0
    def apply_default_rules(self, use_transaction=None):
        if use_transaction is None:
            transaction = FirewallTransaction(self)
        else:
            transaction = use_transaction

        for ipv in [ "ipv4", "ipv6", "eb" ]:
            self.__apply_default_rules(ipv, transaction)

        if self.ipv6_rpfilter_enabled and \
           "raw" in self.get_available_tables("ipv6"):

            # Execute existing transaction
            transaction.execute(True)
            # Start new transaction
            transaction.clear()

            self.ip6tables_backend.apply_rpfilter_rules(transaction, self._log_denied)

            # Execute ipv6_rpfilter transaction, it might fail
            try:
                transaction.execute(True)
            except FirewallError as msg:
                log.warning("Applying rules for ipv6_rpfilter failed: %s", msg)
            # Start new transaction
            transaction.clear()

        else:
            if use_transaction is None:
                transaction.execute(True)
Example #2
0
    def read(self):
        self.clear()
        try:
            f = open(self.filename, "r")
        except Exception as msg:
            log.error("Failed to load '%s': %s", self.filename, msg)
            raise

        for line in f:
            if not line:
                break
            line = line.strip()
            if len(line) < 1 or line[0] in ['#', ';']:
                continue
            # get key/value pair
            pair = [x.strip() for x in line.split("=", 1)]
            if len(pair) != 2:
                continue
            if len(pair[1]) >= 2 and \
               pair[1].startswith('"') and pair[1].endswith('"'):
                pair[1] = pair[1][1:-1]
            if pair[1] == '':
                continue
            elif self._config.get(pair[0]) is not None:
                log.warning("%s: Duplicate option definition: '%s'",
                            self.filename, line.strip())
                continue
            self._config[pair[0]] = pair[1]
        f.close()
Example #3
0
def ipset_reader(filename, path):
    ipset = IPSet()
    if not filename.endswith(".xml"):
        raise FirewallError(INVALID_NAME,
                            "'%s' is missing .xml suffix" % filename)
    ipset.name = filename[:-4]
    ipset.check_name(ipset.name)
    ipset.filename = filename
    ipset.path = path
    ipset.builtin = False if path.startswith(ETC_FIREWALLD) else True
    ipset.default = ipset.builtin
    handler = ipset_ContentHandler(ipset)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "r") as f:
        parser.parse(f)
    del handler
    del parser
    if "timeout" in ipset.options:
        # no entries visible for ipsets with timeout
        log.warning("ipset '%s' uses timeout, entries are removed" % ipset.name)
        del ipset.entries[:]
    if PY2:
        ipset.encode_strings()

    return ipset
Example #4
0
 def startElement(self, name, attrs):
     IO_Object_ContentHandler.startElement(self, name)
     self.item.parser_check_element_attrs(name, attrs)
     if name == "service":
         if "name" in attrs:
             log.warning("Ignoring deprecated attribute name='%s'" % 
                         attrs["name"])
         if "version" in attrs:
             self.item.version = attrs["version"]
     elif name == "short":
         pass
     elif name == "description":
         pass
     elif name == "port":
         if attrs["port"] != "":
             self.item.ports.append((attrs["port"], attrs["protocol"]))
         else:
             self.item.protocols.append(attrs["protocol"])
     elif name == "protocol":
         self.item.protocols.append(attrs["value"])
     elif name == "destination":
         for x in [ "ipv4", "ipv6" ]:
             if x in attrs:
                 if not check_address(x, attrs[x]):
                     raise FirewallError(INVALID_ADDR,
                             "'%s' is not valid %s address" % (attrs[x], x))
                 self.item.destination[x] = attrs[x]
     elif name == "module":
         self.item.modules.append(attrs["name"])
Example #5
0
def ipset_reader(filename, path):
    ipset = IPSet()
    if not filename.endswith(".xml"):
        raise FirewallError(INVALID_NAME,
                            "'%s' is missing .xml suffix" % filename)
    ipset.name = filename[:-4]
    ipset.check_name(ipset.name)
    ipset.filename = filename
    ipset.path = path
    ipset.default = False if path.startswith(ETC_FIREWALLD) else True
    handler = ipset_ContentHandler(ipset)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "r") as f:
        parser.parse(f)
    del handler
    del parser
    if "timeout" in ipset.options:
        # no entries visible for ipsets with timeout
        log.warning("ipset '%s' uses timeout, entries are removed" %
                    ipset.name)
        del ipset.entries[:]
    if PY2:
        ipset.encode_strings()

    return ipset
Example #6
0
    def apply_default_rules(self, use_transaction=None):
        if use_transaction is None:
            transaction = FirewallTransaction(self)
        else:
            transaction = use_transaction

        for backend in self.enabled_backends():
            rules = backend.build_default_rules(self._log_denied)
            transaction.add_rules(backend, rules)

        ipv6_backend = self.get_backend_by_ipv("ipv6")
        if self.ipv6_rpfilter_enabled and \
           "raw" in ipv6_backend.get_available_tables():

            # Execute existing transaction
            transaction.execute(True)
            # Start new transaction
            transaction.clear()

            rules = ipv6_backend.build_rpfilter_rules(self._log_denied)
            transaction.add_rules(ipv6_backend, rules)

            # Execute ipv6_rpfilter transaction, it might fail
            try:
                transaction.execute(True)
            except FirewallError as msg:
                log.warning("Applying rules for ipv6_rpfilter failed: %s", msg)
            # Start new transaction
            transaction.clear()

        else:
            if use_transaction is None:
                transaction.execute(True)
Example #7
0
 def _error2warning(self, f, name, *args):
     # transform errors into warnings
     try:
         f(name, *args)
     except FirewallError as error:
         msg = str(error)
         log.warning("%s: %s" % (name, msg))
Example #8
0
 def startElement(self, name, attrs):
     IO_Object_ContentHandler.startElement(self, name, attrs)
     self.item.parser_check_element_attrs(name, attrs)
     if name == "helper":
         if "version" in attrs:
             self.item.version = attrs["version"]
         if "family" in attrs:
             self.item.check_ipv(attrs["family"])
             self.item.family = attrs["family"]
         if "module" in attrs:
             if not attrs["module"].startswith("nf_conntrack_"):
                 raise FirewallError(
                     errors.INVALID_MODULE,
                     "'%s' does not start with 'nf_conntrack_'" % \
                     attrs["module"])
             if len(attrs["module"].replace("nf_conntrack_", "")) < 1:
                 raise FirewallError(
                     errors.INVALID_MODULE,
                     "Module name '%s' too short" % attrs["module"])
             self.item.module = attrs["module"]
     elif name == "short":
         pass
     elif name == "description":
         pass
     elif name == "port":
         check_port(attrs["port"])
         check_tcpudp(attrs["protocol"])
         entry = (attrs["port"], attrs["protocol"])
         if entry not in self.item.ports:
             self.item.ports.append(entry)
         else:
             log.warning("Port '%s/%s' already set, ignoring.",
                         attrs["port"], attrs["protocol"])
Example #9
0
 def add_icmptype(self, obj):
     orig_ipvs = obj.destination
     if len(orig_ipvs) == 0:
         orig_ipvs = ["ipv4", "ipv6"]
     ipvs = orig_ipvs[:]
     for ipv in orig_ipvs:
         if ipv == "ipv4":
             if not self._fw.ip4tables_enabled:
                 continue
             supported_icmps = self._fw.ip4tables_supported_icmp_types
         elif ipv == "ipv6":
             if not self._fw.ip6tables_enabled:
                 continue
             supported_icmps = self._fw.ip6tables_supported_icmp_types
         else:
             supported_icmps = []
         if obj.name.lower() not in supported_icmps:
             log.warning(
                 "ICMP type '%s' is not supported by the kernel for %s." %
                 (obj.name, ipv))
             ipvs.remove(ipv)
     if len(ipvs) != len(orig_ipvs):
         if len(ipvs) < 1:
             raise FirewallError(errors.INVALID_ICMPTYPE,
                                 "No supported ICMP type.")
         new_obj = copy.deepcopy(obj)
         new_obj.destination = ipvs
         self._icmptypes[obj.name] = new_obj
     else:
         self._icmptypes[obj.name] = obj
Example #10
0
    def read(self):
        self.clear()
        try:
            f = open(self.filename, "r")
        except Exception as msg:
            log.error("Failed to load '%s': %s", self.filename, msg)
            raise

        for line in f:
            if not line:
                break
            line = line.strip()
            if len(line) < 1 or line[0] in ['#', ';']:
                continue
            # get key/value pair
            pair = [ x.strip() for x in line.split("=", 1) ]
            if len(pair) != 2:
                log.warning("%: Invalid option definition: '%s'", self.filename, line.strip())
                continue
            elif pair[1] == '':
                continue
            elif self._config.get(pair[0]) is not None:
                log.warning("%s: Duplicate option definition: '%s'", self.filename, line.strip())
                continue
            self._config[pair[0]] = pair[1]
        f.close()
Example #11
0
 def endElement(self, name):
     IO_Object_ContentHandler.endElement(self, name)
     if name == "entry":
         if self._element not in self.item.entries:
             self.item.entries.append(self._element)
         else:
             log.warning("Entry %s already set, ignoring.", self._element)
Example #12
0
 def startElement(self, name, attrs):
     IO_Object_ContentHandler.startElement(self, name, attrs)
     self.item.parser_check_element_attrs(name, attrs)
     if name == "helper":
         if "version" in attrs:
             self.item.version = attrs["version"]
         if "family" in attrs:
             self.item.check_ipv(attrs["family"])
             self.item.family = attrs["family"]
         if "module" in attrs:
             if not attrs["module"].startswith("nf_conntrack_"):
                 raise FirewallError(
                     errors.INVALID_MODULE,
                     "'%s' does not start with 'nf_conntrack_'" % \
                     attrs["module"])
             if len(attrs["module"].replace("nf_conntrack_", "")) < 1:
                 raise FirewallError(
                     errors.INVALID_MODULE,
                     "Module name '%s' too short" % attrs["module"])
             self.item.module = attrs["module"]
     elif name == "short":
         pass
     elif name == "description":
         pass
     elif name == "port":
         check_port(attrs["port"])
         check_tcpudp(attrs["protocol"])
         entry = (attrs["port"], attrs["protocol"])
         if entry not in self.item.ports:
             self.item.ports.append(entry)
         else:
             log.warning("Port '%s/%s' already set, ignoring.",
                         attrs["port"], attrs["protocol"])
Example #13
0
    def apply_default_rules(self, use_transaction=None):
        if use_transaction is None:
            transaction = FirewallTransaction(self)
        else:
            transaction = use_transaction

        for ipv in self.enabled_backends():
            self.__apply_default_rules(ipv, transaction)

        if self.ipv6_rpfilter_enabled and \
           "raw" in self.get_ipv_backend("ipv6").get_available_tables():

            # Execute existing transaction
            transaction.execute(True)
            # Start new transaction
            transaction.clear()

            self.ip6tables_backend.apply_rpfilter_rules(transaction, self._log_denied)

            # Execute ipv6_rpfilter transaction, it might fail
            try:
                transaction.execute(True)
            except FirewallError as msg:
                log.warning("Applying rules for ipv6_rpfilter failed: %s", msg)
            # Start new transaction
            transaction.clear()

        else:
            if use_transaction is None:
                transaction.execute(True)
Example #14
0
    def startElement(self, name, attrs):
        self.item.parser_check_element_attrs(name, attrs)

        if name == "service":
            if "name" in attrs:
                log.warning("Ignoring deprecated attribute name='%s'" % 
                            attrs["name"])
            if "version" in attrs:
                self.item.version = str(attrs["version"])
        elif name == "short":
            pass
        elif name == "description":
            pass
        elif name == "port":
            self.item.ports.append((str(attrs["port"]),
                                       str(attrs["protocol"])))
        elif name == "destination":
            for x in [ "ipv4", "ipv6" ]:
                if x in attrs:
                    s = str(attrs[x])
                    if x == "ipv4" and not functions.checkIPnMask(s):
                        raise FirewallError(INVALID_DESTINATION, s)
                    if x == "ipv6" and not functions.checkIP6nMask(s):
                        raise FirewallError(INVALID_DESTINATION, s)
                    self.item.destination[x] = str(attrs[x])
        elif name == "module":
            self.item.modules.append(str(attrs["name"]))
Example #15
0
 def endElement(self, name):
     IO_Object_ContentHandler.endElement(self, name)
     if name == "entry":
         if self._element not in self.item.entries:
             self.item.entries.append(self._element)
         else:
             log.warning("Entry %s already set, ignoring.", self._element)
Example #16
0
    def startElement(self, name, attrs):
        self.item.parser_check_element_attrs(name, attrs)

        if name == "service":
            if "name" in attrs:
                log.warning("Ignoring deprecated attribute name='%s'" %
                            attrs["name"])
            if "version" in attrs:
                self.item.version = str(attrs["version"])
        elif name == "short":
            pass
        elif name == "description":
            pass
        elif name == "port":
            self.item.ports.append(
                (str(attrs["port"]), str(attrs["protocol"])))
        elif name == "destination":
            for x in ["ipv4", "ipv6"]:
                if x in attrs:
                    s = str(attrs[x])
                    if x == "ipv4" and not functions.checkIPnMask(s):
                        raise FirewallError(INVALID_DESTINATION, s)
                    if x == "ipv6" and not functions.checkIP6nMask(s):
                        raise FirewallError(INVALID_DESTINATION, s)
                    self.item.destination[x] = str(attrs[x])
        elif name == "module":
            self.item.modules.append(str(attrs["name"]))
Example #17
0
 def _error2warning(self, f, name, *args):
     # transform errors into warnings
     try:
         f(name, *args)
     except FirewallError as error:
         msg = str(error)
         log.warning("%s: %s" % (name, msg))
Example #18
0
 def startElement(self, name, attrs):
     IO_Object_ContentHandler.startElement(self, name)
     self.item.parser_check_element_attrs(name, attrs)
     if name == "service":
         if "name" in attrs:
             log.warning("Ignoring deprecated attribute name='%s'" %
                         attrs["name"])
         if "version" in attrs:
             self.item.version = attrs["version"]
     elif name == "short":
         pass
     elif name == "description":
         pass
     elif name == "port":
         self.item.ports.append((attrs["port"], attrs["protocol"]))
     elif name == "destination":
         for x in ["ipv4", "ipv6"]:
             if x in attrs:
                 if not check_address(x, attrs[x]):
                     raise FirewallError(
                         INVALID_ADDR,
                         "'%s' is not valid %s address" % (attrs[x], x))
                 self.item.destination[x] = attrs[x]
     elif name == "module":
         self.item.modules.append(attrs["name"])
Example #19
0
 def add_passthrough(self, ipv, args):
     self._check_ipv(ipv)
     if ipv not in self.passthroughs:
         self.passthroughs[ipv] = [ ]
     if args not in self.passthroughs[ipv]:
         self.passthroughs[ipv].append(args)
     else:
         log.warning("Passthrough '%s' for ipv '%s'" % \
                     ("',".join(args), ipv) + "already in list, ignoring")
Example #20
0
 def add_passthrough(self, ipv, args):
     self._check_ipv(ipv)
     if ipv not in self.passthroughs:
         self.passthroughs[ipv] = []
     if args not in self.passthroughs[ipv]:
         self.passthroughs[ipv].append(args)
     else:
         log.warning("Passthrough '%s' for ipv '%s'" % \
                     ("',".join(args), ipv) + "already in list, ignoring")
Example #21
0
 def add_chain(self, ipv, table, chain):
     self._check_ipv_table(ipv, table)
     key = (ipv, table)
     if key not in self.chains:
         self.chains[key] = []
     if chain not in self.chains[key]:
         self.chains[key].append(chain)
     else:
         log.warning("Chain '%s' for table '%s' with ipv '%s' " % \
                     (chain, table, ipv) + "already in list, ignoring")
Example #22
0
 def add_chain(self, ipv, table, chain):
     self._check_ipv_table(ipv, table)
     key = (ipv, table)
     if key not in self.chains:
         self.chains[key] = [ ]
     if chain not in self.chains[key]:
         self.chains[key].append(chain)
     else:
         log.warning("Chain '%s' for table '%s' with ipv '%s' " % \
                     (chain, table, ipv) + "already in list, ignoring")
Example #23
0
 def __remove_dangling_lock(self):
     if os.path.exists(self.ebtables_lock):
         ret = runProg("pidof", ["-s", "ebtables"])
         ret2 = runProg("pidof", ["-s", "ebtables-restore"])
         if ret[1] == "" and ret2[1] == "":
             log.warning("Removing dangling ebtables lock file: '%s'" % self.ebtables_lock)
             try:
                 os.unlink(self.ebtables_lock)
             except OSError as e:
                 if e.errno != errno.ENOENT:
                     raise
Example #24
0
    def available_tables(self, table=None):
        ret = []
        tables = [table] if table else CHAINS.keys()
        for table in tables:
            try:
                self.__run(["-t", table, "-L"])
                ret.append(table)
            except ValueError:
                log.warning("ebtables table '%s' does not exist." % table)

        return ret
Example #25
0
    def available_tables(self, table=None):
        ret = []
        tables = [ table ] if table else CHAINS.keys()
        for table in tables:
            try:
                self.__run(["-t", table, "-L"])
                ret.append(table)
            except ValueError:
                log.warning("ebtables table '%s' does not exist." % table)

        return ret
Example #26
0
 def __remove_dangling_lock(self):
     if os.path.exists(self.ebtables_lock):
         (status, ret) = runProg("pidof", ["-s", "ebtables"])
         if ret == "":
             log.warning("Removing dangling ebtables lock file: '%s'" %
                         self.ebtables_lock)
             try:
                 os.unlink(self.ebtables_lock)
             except OSError as e:
                 if e.errno != errno.ENOENT:
                     raise
Example #27
0
 def add_rule(self, ipv, table, chain, priority, args):
     key = (ipv, table, chain)
     if key not in self.rules:
         self.rules[key] = LastUpdatedOrderedDict()
     value = (priority, tuple(args))
     if value not in self.rules[key]:
         self.rules[key][value] = priority
     else:
         log.warning("Rule '%s' for table '%s' and chain '%s' " % \
                         ("',".join(args), table, chain)
                     + "with ipv '%s' and priority %d " % (ipv, priority)
                     + "already in list, ignoring")
Example #28
0
 def add_rule(self, ipv, table, chain, priority, args):
     key = (ipv, table, chain)
     if key not in self.rules:
         self.rules[key] = LastUpdatedOrderedDict()
     value = (priority, tuple(args))
     if value not in self.rules[key]:
         self.rules[key][value] = priority
     else:
         log.warning("Rule '%s' for table '%s' and chain '%s' " % \
                         ("',".join(args), table, chain)
                     + "with ipv '%s' and priority %d " % (ipv, priority)
                     + "already in list, ignoring")
Example #29
0
    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        self.item.parser_check_element_attrs(name, attrs)
        if name == "ipset":
            if "type" in attrs:
                if attrs["type"] not in IPSET_TYPES:
                    raise FirewallError(errors.INVALID_TYPE, "%s" % attrs["type"])
                self.item.type = attrs["type"]
            if "version" in attrs:
                self.item.version = attrs["version"]
        elif name == "short":
            pass
        elif name == "description":
            pass
        elif name == "option":
            value = ""
            if "value" in attrs:
                value = attrs["value"]

            if attrs["name"] not in \
               [ "family", "timeout", "hashsize", "maxelem" ]:
                raise FirewallError(
                    errors.INVALID_OPTION,
                    "Unknown option '%s'" % attrs["name"])
            if self.item.type == "hash:mac" and attrs["name"] in [ "family" ]:
                raise FirewallError(
                    errors.INVALID_OPTION,
                    "Unsupported option '%s' for type '%s'" % \
                    (attrs["name"], self.item.type))
            if attrs["name"] in [ "family", "timeout", "hashsize", "maxelem" ] \
               and not value:
                raise FirewallError(
                    errors.INVALID_OPTION,
                    "Missing mandatory value of option '%s'" % attrs["name"])
            if attrs["name"] in [ "timeout", "hashsize", "maxelem" ]:
                try:
                    int_value = int(value)
                except ValueError:
                    raise FirewallError(
                        errors.INVALID_VALUE,
                        "Option '%s': Value '%s' is not an integer" % \
                        (attrs["name"], value))
                if int_value < 0:
                    raise FirewallError(
                        errors.INVALID_VALUE,
                        "Option '%s': Value '%s' is negative" % \
                        (attrs["name"], value))
            if attrs["name"] == "family" and value not in [ "inet", "inet6" ]:
                raise FirewallError(errors.INVALID_FAMILY, value)
            if attrs["name"] not in self.item.options:
                self.item.options[attrs["name"]] = value
            else:
                log.warning("Option %s already set, ignoring.", attrs["name"])
Example #30
0
    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        self.item.parser_check_element_attrs(name, attrs)
        if name == "ipset":
            if "type" in attrs:
                self.item.type = attrs["type"]
            if "version" in attrs:
                self.item.version = attrs["version"]
        elif name == "short":
            pass
        elif name == "description":
            pass
        elif name == "option":
            value = ""
            if "value" in attrs:
                value = attrs["value"]

            if attrs["name"] not in \
               [ "family", "timeout", "hashsize", "maxelem" ]:
                raise FirewallError(
                    errors.INVALID_OPTION,
                    "Unknown option '%s'" % attrs["name"])
            if self.item.type == "hash:mac" and attrs["name"] in [ "family" ]:
                raise FirewallError(
                    errors.INVALID_OPTION,
                    "Unsupported option '%s' for type '%s'" % \
                    (attrs["name"], self.item.type))
            if attrs["name"] in [ "family", "timeout", "hashsize", "maxelem" ] \
               and not value:
                raise FirewallError(
                    errors.INVALID_OPTION,
                    "Missing mandatory value of option '%s'" % attrs["name"])
            if attrs["name"] in [ "timeout", "hashsize", "maxelem" ]:
                try:
                    int_value = int(value)
                except ValueError:
                    raise FirewallError(
                        errors.INVALID_VALUE,
                        "Option '%s': Value '%s' is not an integer" % \
                        (attrs["name"], value))
                if int_value < 0:
                    raise FirewallError(
                        errors.INVALID_VALUE,
                        "Option '%s': Value '%s' is negative" % \
                        (attrs["name"], value))
            if attrs["name"] == "family" and value not in [ "inet", "inet6" ]:
                raise FirewallError(errors.INVALID_FAMILY, value)
            if attrs["name"] not in self.item.options:
                self.item.options[attrs["name"]] = value
            else:
                log.warning("Option %s already set, ignoring.", attrs["name"])
Example #31
0
    def startElement(self, name, attrs):
        IO_Object_ContentHandler.startElement(self, name, attrs)
        self.item.parser_check_element_attrs(name, attrs)

        if name == "icmptype":
            if "name" in attrs:
                log.warning("Ignoring deprecated attribute name='%s'" % attrs["name"])
            if "version" in attrs:
                self.item.version = attrs["version"]
        elif name == "short":
            pass
        elif name == "description":
            pass
        elif name == "destination":
            for x in ["ipv4", "ipv6"]:
                if x in attrs and attrs[x].lower() in ["yes", "true"]:
                    self.item.destination.append(str(x))
Example #32
0
 def _zone_settings(self, enable, zone, transaction):
     settings = self.get_settings(zone)
     for key in settings:
         for args in settings[key]:
             if key == "interfaces":
                 self._interface(enable, zone, args, transaction)
             elif key == "sources":
                 self._source(enable, zone, args[0], args[1], transaction)
             elif key == "icmp_block_inversion":
                 continue
             else:
                 log.warning(
                     "Zone '%s': Unknown setting '%s:%s', "
                     "unable to apply", zone, key, args)
     # ICMP-block-inversion is always applied
     if enable:
         self._icmp_block_inversion(enable, zone, transaction)
Example #33
0
    def _check_tables(self):
        # check if iptables, ip6tables and ebtables are usable, else disable
        if "filter" not in ipXtables.ip4tables_available_tables:
            log.warning("iptables not usable, disabling IPv4 firewall.")
            self.ip4tables_enabled = False

        if "filter" not in ipXtables.ip6tables_available_tables:
            log.warning("ip6tables not usable, disabling IPv6 firewall.")
            self.ip6tables_enabled = False

        if "filter" not in ebtables.ebtables_available_tables:
            log.error("ebtables not usable, disabling ethernet bridge firewall.")
            self.ebtables_enabled = False

        if not self.ip4tables_enabled and not self.ip6tables_enabled:
            log.fatal("No IPv4 and IPv6 firewall.")
            sys.exit(1)
Example #34
0
    def apply_default_rules(self, use_transaction=None):
        if use_transaction is None:
            transaction = FirewallTransaction(self)
        else:
            transaction = use_transaction

        for ipv in [ "ipv4", "ipv6", "eb" ]:
            self.__apply_default_rules(ipv, transaction)

        if self.ipv6_rpfilter_enabled and \
           "raw" in self.get_available_tables("ipv6"):

            # Execute existing transaction
            transaction.execute(True)
            # Start new transaction
            transaction.clear()

            # here is no check for ebtables.restore_noflush_option needed
            # as ebtables is not used in here
            transaction.add_rule("ipv6",
                                 [ "-I", "PREROUTING", "1", "-t", "raw",
                                   "-p", "ipv6-icmp",
                                   "--icmpv6-type=router-advertisement",
                                   "-j", "ACCEPT" ]) # RHBZ#1058505
            transaction.add_rule("ipv6",
                                 [ "-I", "PREROUTING", "2", "-t", "raw",
                                   "-m", "rpfilter", "--invert", "-j", "DROP" ])
            if self._log_denied != "off":
                transaction.add_rule("ipv6",
                                     [ "-I", "PREROUTING", "2", "-t", "raw",
                                       "-m", "rpfilter", "--invert",
                                       "-j", "LOG",
                                       "--log-prefix", "rpfilter_DROP: " ])

            # Execute ipv6_rpfilter transaction, it might fail
            try:
                transaction.execute(True)
            except FirewallError as msg:
                log.warning("Applying rules for ipv6_rpfilter failed: %s", msg)
            # Start new transaction
            transaction.clear()

        else:
            if use_transaction is None:
                transaction.execute(True)
Example #35
0
    def apply_default_rules(self, use_transaction=None):
        if use_transaction is None:
            transaction = FirewallTransaction(self)
        else:
            transaction = use_transaction

        for ipv in [ "ipv4", "ipv6", "eb" ]:
            self.__apply_default_rules(ipv, transaction)

        if self.ipv6_rpfilter_enabled and \
           "raw" in self.get_available_tables("ipv6"):

            # Execute existing transaction
            transaction.execute(True)
            # Start new transaction
            transaction.clear()

            # here is no check for ebtables.restore_noflush_option needed
            # as ebtables is not used in here
            transaction.add_rule("ipv6",
                                 [ "-I", "PREROUTING", "1", "-t", "raw",
                                   "-p", "ipv6-icmp",
                                   "--icmpv6-type=router-advertisement",
                                   "-j", "ACCEPT" ]) # RHBZ#1058505
            transaction.add_rule("ipv6",
                                 [ "-I", "PREROUTING", "2", "-t", "raw",
                                   "-m", "rpfilter", "--invert", "-j", "DROP" ])
            if self._log_denied != "off":
                transaction.add_rule("ipv6",
                                     [ "-I", "PREROUTING", "2", "-t", "raw",
                                       "-m", "rpfilter", "--invert",
                                       "-j", "LOG",
                                       "--log-prefix", "rpfilter_DROP: " ])

            # Execute ipv6_rpfilter transaction, it might fail
            try:
                transaction.execute(True)
            except FirewallError as msg:
                log.warning("Applying rules for ipv6_rpfilter failed: %s", msg)
            # Start new transaction
            transaction.clear()

        else:
            if use_transaction is None:
                transaction.execute(True)
Example #36
0
def common_endElement(obj, name):
    if name == "rule":
        if not obj._rule_error:
            try:
                obj._rule.check()
            except Exception as e:
                log.warning("%s: %s", e, str(obj._rule))
            else:
                if str(obj._rule) not in obj.item.rules_str:
                    obj.item.rules.append(obj._rule)
                    obj.item.rules_str.append(str(obj._rule))
                else:
                    log.warning("Rule '%s' already set, ignoring.",
                                str(obj._rule))
        obj._rule = None
        obj._rule_error = False
    elif name in ["accept", "reject", "drop", "mark", "log", "audit"]:
        obj._limit_ok = None
Example #37
0
    def startElement(self, name, attrs):
        self.item.parser_check_element_attrs(name, attrs)

        if name == "icmptype":
            if "name" in attrs:
                log.warning("Ignoring deprecated attribute name='%s'" %
                            attrs["name"])
            if "version" in attrs:
                self.item.version = str(attrs["version"])
        elif name == "short":
            pass
        elif name == "description":
            pass
        elif name == "destination":
            for x in ["ipv4", "ipv6"]:
                if x in attrs and \
                        attrs[x].lower() in [ "yes", "true" ]:
                    self.item.destination.append(str(x))
Example #38
0
    def _check_tables(self):
        # check if iptables, ip6tables and ebtables are usable, else disable
        if "filter" not in ipXtables.ip4tables_available_tables:
            log.warning("iptables not usable, disabling IPv4 firewall.")
            self.ip4tables_enabled = False

        if "filter" not in ipXtables.ip6tables_available_tables:
            log.warning("ip6tables not usable, disabling IPv6 firewall.")
            self.ip6tables_enabled = False

        if "filter" not in ebtables.ebtables_available_tables:
            log.error(
                "ebtables not usable, disabling ethernet bridge firewall.")
            self.ebtables_enabled = False

        if not self.ip4tables_enabled and not self.ip6tables_enabled:
            log.fatal("No IPv4 and IPv6 firewall.")
            sys.exit(1)
Example #39
0
    def endElement(self, name):
        IO_Object_ContentHandler.endElement(self, name)

        if name == "rule":
            if not self._rule_error:
                try:
                    self._rule.check()
                except Exception as e:
                    log.warning("%s: %s", e, str(self._rule))
                else:
                    if str(self._rule) not in [str(x) for x in self.item.rules]:
                        self.item.rules.append(self._rule)
                    else:
                        log.warning("Rule '%s' already set, ignoring.", str(self._rule))
            self._rule = None
            self._rule_error = False
        elif name in ["accept", "reject", "drop", "mark", "log", "audit"]:
            self._limit_ok = None
Example #40
0
    def set_config(self, config):
        (_chains, _rules) = config
        for table_id in _chains:
            (ipv, table) = table_id
            for chain in _chains[table_id]:
                if not self.query_chain(ipv, table, chain):
                    try:
                        self.add_chain(ipv, table, chain)
                    except FirewallError as error:
                        log.warning(str(error))

        for chain_id in _rules:
            (ipv, table, chain) = chain_id
            for (priority, args) in _rules[chain_id]:
                if not self.query_rule(ipv, table, chain, priority, args):
                    try:
                        self.add_rule(ipv, table, chain, priority, args)
                    except FirewallError as error:
                        log.warning(str(error))
Example #41
0
def ipset_reader(filename, path):
    ipset = IPSet()
    if not filename.endswith(".xml"):
        raise FirewallError(errors.INVALID_NAME,
                            "'%s' is missing .xml suffix" % filename)
    ipset.name = filename[:-4]
    ipset.check_name(ipset.name)
    ipset.filename = filename
    ipset.path = path
    ipset.builtin = False if path.startswith(ETC_FIREWALLD) else True
    ipset.default = ipset.builtin
    handler = ipset_ContentHandler(ipset)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "r") as f:
        try:
            parser.parse(f)
        except sax.SAXParseException as msg:
            raise FirewallError(errors.INVALID_IPSET,
                                "not a valid ipset file: %s" % \
                                msg.getException())
    del handler
    del parser
    if "timeout" in ipset.options and len(ipset.entries) > 0:
        # no entries visible for ipsets with timeout
        log.warning("ipset '%s': timeout option is set, entries are ignored",
                    ipset.name)
        del ipset.entries[:]
    i = 0
    while i < len(ipset.entries):
        try:
            ipset.check_entry(ipset.entries[i], ipset.options, ipset.type)
        except FirewallError as e:
            log.warning("%s, ignoring.", e)
            ipset.entries.pop(i)
        else:
            i += 1
    if PY2:
        ipset.encode_strings()

    return ipset
Example #42
0
def ipset_reader(filename, path):
    ipset = IPSet()
    if not filename.endswith(".xml"):
        raise FirewallError(errors.INVALID_NAME,
                            "'%s' is missing .xml suffix" % filename)
    ipset.name = filename[:-4]
    ipset.check_name(ipset.name)
    ipset.filename = filename
    ipset.path = path
    ipset.builtin = False if path.startswith(ETC_FIREWALLD) else True
    ipset.default = ipset.builtin
    handler = ipset_ContentHandler(ipset)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "r") as f:
        try:
            parser.parse(f)
        except sax.SAXParseException as msg:
            raise FirewallError(errors.INVALID_IPSET,
                                "not a valid ipset file: %s" % \
                                msg.getException())
    del handler
    del parser
    if "timeout" in ipset.options and len(ipset.entries) > 0:
        # no entries visible for ipsets with timeout
        log.warning("ipset '%s': timeout option is set, entries are ignored",
                    ipset.name)
        del ipset.entries[:]
    i = 0
    while i < len(ipset.entries):
        try:
            ipset.check_entry(ipset.entries[i], ipset.options, ipset.type)
        except FirewallError as e:
            log.warning("%s, ignoring.", e)
            ipset.entries.pop(i)
        else:
            i += 1
    if PY2:
        ipset.encode_strings()

    return ipset
Example #43
0
 def _zone_settings(self, enable, zone, transaction):
     settings = self.get_settings(zone)
     for key in settings:
         for args in settings[key]:
             if key == "interfaces":
                 self._interface(enable, zone, args, transaction)
             elif key == "sources":
                 self._source(enable, zone, args[0], args[1], transaction)
             elif key == "icmp_block_inversion":
                 continue
             elif key == "forward":
                 # no need to call this when applying the zone as the rules
                 # will be generated when adding the interfaces/sources
                 pass
             else:
                 log.warning("Zone '%s': Unknown setting '%s:%s', "
                             "unable to apply", zone, key, args)
     # ICMP-block-inversion is always applied
     if enable:
         self._icmp_block_inversion(enable, zone, transaction)
Example #44
0
 def _impl(*args, **kwargs):
     try:
         return func(*args, **kwargs)
     except FirewallError as error:
         code = FirewallError.get_code(str(error))
         if code in [
                 errors.ALREADY_ENABLED, errors.NOT_ENABLED,
                 errors.ZONE_ALREADY_SET, errors.ALREADY_SET
         ]:
             log.warning(str(error))
         else:
             log.debug1(traceback.format_exc())
             log.error(str(error))
         raise FirewallDBusException(str(error))
     except DBusException as ex:
         # only log DBusExceptions once
         raise ex
     except Exception as ex:
         log.exception()
         raise FirewallDBusException(str(ex))
Example #45
0
    def endElement(self, name):
        IO_Object_ContentHandler.endElement(self, name)

        if name == "rule":
            if not self._rule_error:
                try:
                    self._rule.check()
                except Exception as e:
                    log.warning("%s: %s", e, str(self._rule))
                else:
                    if str(self._rule) not in \
                       [ str(x) for x in self.item.rules ]:
                        self.item.rules.append(self._rule)
                    else:
                        log.warning("Rule '%s' already set, ignoring.",
                                    str(self._rule))
            self._rule = None
            self._rule_error = False
        elif name in ["accept", "reject", "drop", "mark", "log", "audit"]:
            self._limit_ok = None
Example #46
0
def dbus_handle_exceptions(func, *args, **kwargs):
    """Decorator to handle exceptions, log and report them into D-Bus

    :Raises DBusException: on a firewall error code problems.
    """
    try:
        return func(*args, **kwargs)
    except FirewallError as error:
        code = FirewallError.get_code(str(error))
        if code in [ errors.ALREADY_ENABLED, errors.NOT_ENABLED,
                     errors.ZONE_ALREADY_SET, errors.ALREADY_SET ]:
            log.warning(str(error))
        else:
            log.error(str(error))
        raise FirewallDBusException(str(error))
    except DBusException as ex:
        # only log DBusExceptions once
        raise ex
    except Exception as ex:
        log.exception()
        raise FirewallDBusException(str(ex))
Example #47
0
    def _check_tables(self):
        # check if iptables, ip6tables and ebtables are usable, else disable
        if self.ip4tables_enabled and \
           "filter" not in self.get_available_tables("ipv4"):
            log.warning("iptables not usable, disabling IPv4 firewall.")
            self.ip4tables_enabled = False

        if self.ip6tables_enabled and \
           "filter" not in self.get_available_tables("ipv6"):
            log.warning("ip6tables not usable, disabling IPv6 firewall.")
            self.ip6tables_enabled = False

        if self.ebtables_enabled and \
           "filter" not in self.get_available_tables("eb"):
            log.error("ebtables not usable, disabling ethernet bridge firewall.")
            self.ebtables_enabled = False

        # is there at least support for ipv4 or ipv6
        if not self.ip4tables_enabled and not self.ip6tables_enabled:
            log.fatal("No IPv4 and IPv6 firewall.")
            sys.exit(1)
Example #48
0
    def set_config(self, conf, use_transaction=None):
        if use_transaction is None:
            transaction = self.new_transaction()
        else:
            transaction = use_transaction

        (_chains, _rules, _passthroughs) = conf
        for table_id in _chains:
            (ipv, table) = table_id
            for chain in _chains[table_id]:
                if not self.query_chain(ipv, table, chain):
                    try:
                        self.add_chain(ipv, table, chain, use_transaction=transaction)
                    except FirewallError as error:
                        log.warning(str(error))

        for chain_id in _rules:
            (ipv, table, chain) = chain_id
            for (priority, args) in _rules[chain_id]:
                if not self.query_rule(ipv, table, chain, priority, args):
                    try:
                        self.add_rule(ipv, table, chain, priority, args, use_transaction=transaction)
                    except FirewallError as error:
                        log.warning(str(error))

        for ipv in _passthroughs:
            for args in _passthroughs[ipv]:
                if not self.query_passthrough(ipv, args):
                    try:
                        self.add_passthrough(ipv, args, use_transaction=transaction)
                    except FirewallError as error:
                        log.warning(str(error))

        if use_transaction is None:
            transaction.execute(True)
Example #49
0
    def _check_tables(self):
        # check if iptables, ip6tables and ebtables are usable, else disable
        if self.ip4tables_enabled and \
           "filter" not in self.get_available_tables("ipv4"):
            log.warning("iptables not usable, disabling IPv4 firewall.")
            self.ip4tables_enabled = False

        if self.ip6tables_enabled and \
           "filter" not in self.get_available_tables("ipv6"):
            log.warning("ip6tables not usable, disabling IPv6 firewall.")
            self.ip6tables_enabled = False

        if self.ebtables_enabled and \
           "filter" not in self.get_available_tables("eb"):
            log.error(
                "ebtables not usable, disabling ethernet bridge firewall.")
            self.ebtables_enabled = False

        # is there at least support for ipv4 or ipv6
        if not self.ip4tables_enabled and not self.ip6tables_enabled:
            log.fatal("No IPv4 and IPv6 firewall.")
            sys.exit(1)
Example #50
0
 def _zone_settings(self, enable, zone, transaction):
     for key in ["interfaces", "sources", "forward", "icmp_block_inversion"]:
         args_list = getattr(self.get_zone(zone), key)
         if isinstance(args_list, bool):
             args_list = [args_list]
         for args in args_list:
             if key == "interfaces":
                 self._interface(enable, zone, args, transaction)
             elif key == "sources":
                 ipv = self.check_source(args)
                 self._source(enable, zone, ipv, args, transaction)
             elif key == "icmp_block_inversion":
                 continue
             elif key == "forward":
                 # no need to call this when applying the zone as the rules
                 # will be generated when adding the interfaces/sources
                 pass
             else:
                 log.warning("Zone '%s': Unknown setting '%s:%s', "
                             "unable to apply", zone, key, args)
     # ICMP-block-inversion is always applied
     if enable:
         self._icmp_block_inversion(enable, zone, transaction)
Example #51
0
def ipset_reader(filename, path):
    ipset = IPSet()
    if not filename.endswith(".xml"):
        raise FirewallError(errors.INVALID_NAME,
                            "'%s' is missing .xml suffix" % filename)
    ipset.name = filename[:-4]
    ipset.check_name(ipset.name)
    ipset.filename = filename
    ipset.path = path
    ipset.builtin = False if path.startswith(config.ETC_FIREWALLD) else True
    ipset.default = ipset.builtin
    handler = ipset_ContentHandler(ipset)
    parser = sax.make_parser()
    parser.setContentHandler(handler)
    name = "%s/%s" % (path, filename)
    with open(name, "rb") as f:
        source = sax.InputSource(None)
        source.setByteStream(f)
        try:
            parser.parse(source)
        except sax.SAXParseException as msg:
            raise FirewallError(errors.INVALID_IPSET,
                                "not a valid ipset file: %s" % \
                                msg.getException())
    del handler
    del parser
    if "timeout" in ipset.options and ipset.options["timeout"] != "0" and \
       len(ipset.entries) > 0:
        # no entries visible for ipsets with timeout
        log.warning("ipset '%s': timeout option is set, entries are ignored",
                    ipset.name)
        del ipset.entries[:]
    i = 0
    entries_set = set()
    while i < len(ipset.entries):
        if ipset.entries[i] in entries_set:
            log.warning("Entry %s already set, ignoring.", ipset.entries[i])
            ipset.entries.pop(i)
        else:
            try:
                ipset.check_entry(ipset.entries[i], ipset.options, ipset.type)
            except FirewallError as e:
                log.warning("%s, ignoring.", e)
                ipset.entries.pop(i)
            else:
                entries_set.add(ipset.entries[i])
                i += 1
    del entries_set

    return ipset
Example #52
0
def zone_writer(zone, path=None):
    _path = path if path else zone.path

    if zone.filename:
        name = "%s/%s" % (_path, zone.filename)
    else:
        name = "%s/%s.xml" % (_path, zone.name)

    if os.path.exists(name):
        try:
            shutil.copy2(name, "%s.old" % name)
        except Exception as msg:
            raise IOError("Backup of '%s' failed: %s" % (name, msg))

    dirpath = os.path.dirname(name)
    if dirpath.startswith(ETC_FIREWALLD) and not os.path.exists(dirpath):
        if not os.path.exists(ETC_FIREWALLD):
            os.mkdir(ETC_FIREWALLD, 0o750)
        os.mkdir(dirpath, 0o750)

    f = io.open(name, mode='wt', encoding='UTF-8')
    handler = IO_Object_XMLGenerator(f)
    handler.startDocument()

    # start zone element
    attrs = {}
    if zone.version and zone.version != "":
        attrs["version"] = zone.version
    if zone.target != DEFAULT_ZONE_TARGET:
        attrs["target"] = zone.target
    handler.startElement("zone", attrs)
    handler.ignorableWhitespace("\n")

    # short
    if zone.short and zone.short != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("short", { })
        handler.characters(zone.short)
        handler.endElement("short")
        handler.ignorableWhitespace("\n")

    # description
    if zone.description and zone.description != "":
        handler.ignorableWhitespace("  ")
        handler.startElement("description", { })
        handler.characters(zone.description)
        handler.endElement("description")
        handler.ignorableWhitespace("\n")

    # interfaces
    for interface in uniqify(zone.interfaces):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("interface", { "name": interface })
        handler.ignorableWhitespace("\n")

    # source
    for source in uniqify(zone.sources):
        handler.ignorableWhitespace("  ")
        if "ipset:" in source:
            handler.simpleElement("source", { "ipset": source[6:] })
        else:
            handler.simpleElement("source", { "address": source })
        handler.ignorableWhitespace("\n")

    # services
    for service in uniqify(zone.services):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("service", { "name": service })
        handler.ignorableWhitespace("\n")

    # ports
    for port in uniqify(zone.ports):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("port", { "port": port[0], "protocol": port[1] })
        handler.ignorableWhitespace("\n")

    # protocols
    for protocol in uniqify(zone.protocols):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("protocol", { "value": protocol })
        handler.ignorableWhitespace("\n")

    # icmp-blocks
    for icmp in uniqify(zone.icmp_blocks):
        handler.ignorableWhitespace("  ")
        handler.simpleElement("icmp-block", { "name": icmp })
        handler.ignorableWhitespace("\n")

    # masquerade
    if zone.masquerade:
        handler.ignorableWhitespace("  ")
        handler.simpleElement("masquerade", { })
        handler.ignorableWhitespace("\n")

    # forward-ports
    for forward in uniqify(zone.forward_ports):
        handler.ignorableWhitespace("  ")
        attrs = { "port": forward[0], "protocol": forward[1] }
        if forward[2] and forward[2] != "" :
            attrs["to-port"] = forward[2]
        if forward[3] and forward[3] != "" :
            attrs["to-addr"] = forward[3]
        handler.simpleElement("forward-port", attrs)
        handler.ignorableWhitespace("\n")

    # rules
    for rule in zone.rules:
        attrs = { }
        if rule.family:
            attrs["family"] = rule.family
        handler.ignorableWhitespace("  ")
        handler.startElement("rule", attrs)
        handler.ignorableWhitespace("\n")

        # source
        if rule.source:
            attrs = { }
            if rule.source.addr:
                attrs["address"] = rule.source.addr
            if rule.source.mac:
                attrs["mac"] = rule.source.mac
            if rule.source.ipset:
                attrs["ipset"] = rule.source.ipset
            if rule.source.invert:
                attrs["invert"] = "True"
            handler.ignorableWhitespace("    ")
            handler.simpleElement("source", attrs)
            handler.ignorableWhitespace("\n")

        # destination
        if rule.destination:
            attrs = { "address": rule.destination.addr }
            if rule.destination.invert:
                attrs["invert"] = "True"
            handler.ignorableWhitespace("    ")
            handler.simpleElement("destination", attrs)
            handler.ignorableWhitespace("\n")

        # element
        if rule.element:
            element = ""
            attrs = { }

            if type(rule.element) == Rich_Service:
                element = "service"
                attrs["name"] = rule.element.name
            elif type(rule.element) == Rich_Port:
                element = "port"
                attrs["port"] = rule.element.port
                attrs["protocol"] = rule.element.protocol
            elif type(rule.element) == Rich_Protocol:
                element = "protocol"
                attrs["value"] = rule.element.value
            elif type(rule.element) == Rich_Masquerade:
                element = "masquerade"
            elif type(rule.element) == Rich_IcmpBlock:
                element = "icmp-block"
                attrs["name"] = rule.element.name
            elif type(rule.element) == Rich_ForwardPort:
                element = "forward-port"
                attrs["port"] = rule.element.port
                attrs["protocol"] = rule.element.protocol
                if rule.element.to_port != "":
                    attrs["to-port"] = rule.element.to_port
                if rule.element.to_address != "":
                    attrs["to-addr"] = rule.element.to_address
            else:
                log.warning("Unknown element '%s'", type(rule.element))

            handler.ignorableWhitespace("    ")
            handler.simpleElement(element, attrs)
            handler.ignorableWhitespace("\n")

        # rule.element

        # log
        if rule.log:
            attrs = { }
            if rule.log.prefix:
                attrs["prefix"] = rule.log.prefix
            if rule.log.level:
                attrs["level"] = rule.log.level
            if rule.log.limit:
                handler.ignorableWhitespace("    ")
                handler.startElement("log", attrs)
                handler.ignorableWhitespace("\n      ")
                handler.simpleElement("limit",
                                      { "value": rule.log.limit.value })
                handler.ignorableWhitespace("\n    ")
                handler.endElement("log")
            else:
                handler.ignorableWhitespace("    ")
                handler.simpleElement("log", attrs)
            handler.ignorableWhitespace("\n")

        # audit
        if rule.audit:
            attrs = {}
            if rule.audit.limit:
                handler.ignorableWhitespace("    ")
                handler.startElement("audit", { })
                handler.ignorableWhitespace("\n      ")
                handler.simpleElement("limit",
                                      { "value": rule.audit.limit.value })
                handler.ignorableWhitespace("\n    ")
                handler.endElement("audit")
            else:
                handler.ignorableWhitespace("    ")
                handler.simpleElement("audit", attrs)
            handler.ignorableWhitespace("\n")

        # action
        if rule.action:
            action = ""
            attrs = { }
            if type(rule.action) == Rich_Accept:
                action = "accept"
            elif type(rule.action) == Rich_Reject:
                action = "reject"
                if rule.action.type:
                    attrs["type"] = rule.action.type
            elif type(rule.action) == Rich_Drop:
                action = "drop"
            else:
                log.warning("Unknown action '%s'", type(rule.action))
            if rule.action.limit:
                handler.ignorableWhitespace("    ")
                handler.startElement(action, attrs)
                handler.ignorableWhitespace("\n      ")
                handler.simpleElement("limit",
                                      { "value": rule.action.limit.value })
                handler.ignorableWhitespace("\n    ")
                handler.endElement(action)
            else:
                handler.ignorableWhitespace("    ")
                handler.simpleElement(action, attrs)
            handler.ignorableWhitespace("\n")

        handler.ignorableWhitespace("  ")
        handler.endElement("rule")
        handler.ignorableWhitespace("\n")

    # end zone element
    handler.endElement("zone")
    handler.ignorableWhitespace("\n")
    handler.endDocument()
    f.close()
    del handler
Example #53
0
    def execute(self, enable):
        log.debug4("%s.execute(%s)" % (type(self), enable))

        rules, modules = self.prepare(enable)

        # pre
        self.pre()

        # stage 1: apply rules
        error = False
        done = [ ]
        for ipv in rules:
            try:
                self.fw.rules(ipv, rules[ipv])
            except Exception as msg:
                error = True
                if not self.generous_mode:
                    log.warning(msg)
            else:
                done.append(ipv)

        if error and self.generous_mode:
            for ipv in rules:
                if ipv in done:
                    continue
                for rule in rules[ipv]:
                    try:
                        self.fw.rule(ipv, rule)
                    except Exception as msg:
                        log.warning(msg)
                done.append(ipv)
            error = False

        # stage 2: load modules
        if not error:
            module_return = self.fw.handle_modules(modules, enable)
            if module_return:
                (cleanup_modules, msg) = module_return
                if cleanup_modules is not None:
                    error = True
                    self.fw.handle_modules(cleanup_modules, not enable)

        # error case: revert rules
        if error:
            undo_rules = { }
            for ipv in done:
                undo_rules[ipv] = [ ]
                for rule in reversed(rules[ipv]):
                    undo_rules[ipv].append(reverse_rule(rule))
            for ipv in undo_rules:
                try:
                    self.fw.rules(ipv, undo_rules[ipv])
                except Exception as msg:
                    log.error(msg)
            # call failure functions
            for (func, args) in self.fail_funcs:
                try:
                    func(*args)
                except Exception as msg:
                    log.error("Calling fail func %s(%s) failed: %s" % \
                              (func, args, msg))

            raise FirewallError(errors.COMMAND_FAILED)

        # post
        self.post()
Example #54
0
    def _start(self):
        # initialize firewall
        default_zone = FALLBACK_ZONE

        # load firewalld config
        log.debug1("Loading firewalld config file '%s'", FIREWALLD_CONF)
        try:
            self._firewalld_conf.read()
        except Exception as msg:
            log.warning("Using fallback firewalld configuration settings.")
        else:
            if self._firewalld_conf.get("DefaultZone"):
                default_zone = self._firewalld_conf.get("DefaultZone")

            if self._firewalld_conf.get("MinimalMark"):
                self._min_mark = int(self._firewalld_conf.get("MinimalMark"))

            if self._firewalld_conf.get("CleanupOnExit"):
                value = self._firewalld_conf.get("CleanupOnExit")
                if value is not None and value.lower() in [ "no", "false" ]:
                    self.cleanup_on_exit = False

            if self._firewalld_conf.get("Lockdown"):
                value = self._firewalld_conf.get("Lockdown")
                if value is not None and value.lower() in [ "yes", "true" ]:
                    log.debug1("Lockdown is enabled")
                    try:
                        self.policies.enable_lockdown()
                    except FirewallError:
                        # already enabled, this is probably reload
                        pass

            if self._firewalld_conf.get("IPv6_rpfilter"):
                value = self._firewalld_conf.get("IPv6_rpfilter")
                if value is not None:
                    if value.lower() in [ "no", "false" ]:
                        self.ipv6_rpfilter_enabled = False
                    if value.lower() in [ "yes", "true" ]:
                        self.ipv6_rpfilter_enabled = True
            if self.ipv6_rpfilter_enabled:
                log.debug1("IPv6 rpfilter is enabled")
            else:
                log.debug1("IPV6 rpfilter is disabled")

        self.config.set_firewalld_conf(copy.deepcopy(self._firewalld_conf))

        # apply default rules
        self._apply_default_rules()

        # load lockdown whitelist
        log.debug1("Loading lockdown whitelist")
        try:
            self.policies.lockdown_whitelist.read()
        except Exception as msg:
            if self.policies.query_lockdown():
                log.error("Failed to load lockdown whitelist '%s': %s",
                      self.policies.lockdown_whitelist.filename, msg)
            else:
                log.debug1("Failed to load lockdown whitelist '%s': %s",
                      self.policies.lockdown_whitelist.filename, msg)

        # copy policies to config interface
        self.config.set_policies(copy.deepcopy(self.policies))

        # load icmptype files
        self._loader(FIREWALLD_ICMPTYPES, "icmptype")
        self._loader(ETC_FIREWALLD_ICMPTYPES, "icmptype")

        if len(self.icmptype.get_icmptypes()) == 0:
            log.error("No icmptypes found.")

        # load service files
        self._loader(FIREWALLD_SERVICES, "service")
        self._loader(ETC_FIREWALLD_SERVICES, "service")

        if len(self.service.get_services()) == 0:
            log.error("No services found.")

        # load zone files
        self._loader(FIREWALLD_ZONES, "zone")
        self._loader(ETC_FIREWALLD_ZONES, "zone")

        if len(self.zone.get_zones()) == 0:
            log.fatal("No zones found.")
            sys.exit(1)

        # check minimum required zones
        error = False
        for z in [ "block", "drop", "trusted" ]:
            if z not in self.zone.get_zones():
                log.fatal("Zone '%s' is not available.", z)
                error = True
        if error:
            sys.exit(1)

        # apply settings for loaded zones
        self.zone.apply_zones()

        # load direct rules
        obj = Direct(FIREWALLD_DIRECT)
        if os.path.exists(FIREWALLD_DIRECT):
            log.debug1("Loading direct rules file '%s'" % FIREWALLD_DIRECT)
            try:
                obj.read()
            except Exception as msg:
                log.debug1("Failed to load direct rules file '%s': %s",
                           FIREWALLD_DIRECT, msg)
            else:
                self.direct.set_permanent_config(obj)
        self.config.set_direct(copy.deepcopy(obj))

        # check if default_zone is a valid zone
        if default_zone not in self.zone.get_zones():
            if "public" in self.zone.get_zones():
                zone = "public"
            elif "external" in self.zone.get_zones():
                zone = "external"
            else:
                zone = "block" # block is a base zone, therefore it has to exist

            log.error("Default zone '%s' is not valid. Using '%s'.",
                      default_zone, zone)
            default_zone = zone
        else:
            log.debug1("Using default zone '%s'", default_zone)

        self._default_zone = self.check_zone(default_zone)
        self.zone.change_default_zone(None, self._default_zone)

        self._state = "RUNNING"
Example #55
0
 def startElement(self, name, attrs):
     IO_Object_ContentHandler.startElement(self, name)
     self.item.parser_check_element_attrs(name, attrs)
     if name == "service":
         if "name" in attrs:
             log.warning("Ignoring deprecated attribute name='%s'",
                         attrs["name"])
         if "version" in attrs:
             self.item.version = attrs["version"]
     elif name == "short":
         pass
     elif name == "description":
         pass
     elif name == "port":
         if attrs["port"] != "":
             check_port(attrs["port"])
             check_tcpudp(attrs["protocol"])
             entry = (attrs["port"], attrs["protocol"])
             if entry not in self.item.ports:
                 self.item.ports.append(entry)
             else:
                 log.warning("Port '%s/%s' already set, ignoring.",
                             attrs["port"], attrs["protocol"])
         else:
             check_protocol(attrs["protocol"])
             if attrs["protocol"] not in self.item.protocols:
                 self.item.protocols.append(attrs["protocol"])
             else:
                 log.warning("Protocol '%s' already set, ignoring.",
                             attrs["protocol"])
     elif name == "protocol":
         check_protocol(attrs["value"])
         if attrs["value"] not in self.item.protocols:
             self.item.protocols.append(attrs["value"])
         else:
             log.warning("Protocol '%s' already set, ignoring.",
                         attrs["value"])
     elif name == "destination":
         for x in [ "ipv4", "ipv6" ]:
             if x in attrs:
                 check_address(x, attrs[x])
                 if x in self.item.destination:
                     log.warning("Destination address for '%s' already set, ignoring",
                                 x)
                 else:
                     self.item.destination[x] = attrs[x]
     elif name == "module":
         if attrs["name"].startswith("nf_conntrack_") and \
            len(attrs["name"].replace("nf_conntrack_", "")) > 0:
             if attrs["name"] not in self.item.modules:
                 self.item.modules.append(attrs["name"])
             else:
                 log.warning("Module '%s' already set, ignoring.",
                             attrs["name"])
         else:
             log.warning("Invalid module '%s'", attrs["name"])
Example #56
0
    def _start_check(self):
        try:
            self.ipset_backend.list()
        except ValueError:
            log.warning("ipset not usable, disabling ipset usage in firewall.")
            # ipset is not usable, no supported types
            self.ipset_enabled = False
            self.ipset_supported_types = [ ]
        else:
            # ipset is usable, get all supported types
            self.ipset_supported_types = self.ipset_backend.supported_types()

        self.ip4tables_backend.fill_exists()
        if not self.ip4tables_backend.restore_command_exists:
            if self.ip4tables_backend.command_exists:
                log.warning("iptables-restore is missing, using "
                            "individual calls for IPv4 firewall.")
            else:
                log.warning("iptables-restore and iptables are missing, "
                            "disabling IPv4 firewall.")
                self.ip4tables_enabled = False

        self.ip6tables_backend.fill_exists()
        if not self.ip6tables_backend.restore_command_exists:
            if self.ip6tables_backend.command_exists:
                log.warning("ip6tables-restore is missing, using "
                            "individual calls for IPv6 firewall.")
            else:
                log.warning("ip6tables-restore and ip6tables are missing, "
                            "disabling IPv6 firewall.")
                self.ip6tables_enabled = False

        self.ebtables_backend.fill_exists()
        if not self.ebtables_backend.restore_command_exists:
            if self.ebtables_backend.command_exists:
                log.warning("ebtables-restore is missing, using "
                            "individual calls for bridge firewall.")
            else:
                log.warning("ebtables-restore and ebtables are missing, "
                            "disabling bridge firewall.")
                self.ebtables_enabled = False

        if self.ebtables_enabled and not self._individual_calls and \
           not self.ebtables_backend.restore_noflush_option:
            log.debug1("ebtables-restore is not supporting the --noflush "
                       "option, will therefore not be used")

        if os.path.exists(config.COMMANDS["modinfo"]):
            self.nf_conntrack_helpers = functions.get_nf_conntrack_helpers()
            if len(self.nf_conntrack_helpers) > 0:
                log.debug1("Conntrack helpers supported by the kernel:")
                for key,values in self.nf_conntrack_helpers.items():
                    log.debug1("  %s: %s", key, ", ".join(values))
            else:
                log.debug1("No conntrack helpers supported by the kernel.")
        else:
            self.nf_conntrack_helpers = { }
            log.warning("modinfo command is missing, not able to detect conntrack helpers.")
Example #57
0
    def _start(self, reload=False, complete_reload=False):
        # initialize firewall
        default_zone = config.FALLBACK_ZONE

        # load firewalld config
        log.debug1("Loading firewalld config file '%s'", config.FIREWALLD_CONF)
        try:
            self._firewalld_conf.read()
        except Exception as msg:
            log.warning(msg)
            log.warning("Using fallback firewalld configuration settings.")
        else:
            if self._firewalld_conf.get("DefaultZone"):
                default_zone = self._firewalld_conf.get("DefaultZone")

            if self._firewalld_conf.get("MinimalMark"):
                self._min_mark = int(self._firewalld_conf.get("MinimalMark"))

            if self._firewalld_conf.get("CleanupOnExit"):
                value = self._firewalld_conf.get("CleanupOnExit")
                if value is not None and value.lower() in [ "no", "false" ]:
                    self.cleanup_on_exit = False

            if self._firewalld_conf.get("Lockdown"):
                value = self._firewalld_conf.get("Lockdown")
                if value is not None and value.lower() in [ "yes", "true" ]:
                    log.debug1("Lockdown is enabled")
                    try:
                        self.policies.enable_lockdown()
                    except FirewallError:
                        # already enabled, this is probably reload
                        pass

            if self._firewalld_conf.get("IPv6_rpfilter"):
                value = self._firewalld_conf.get("IPv6_rpfilter")
                if value is not None:
                    if value.lower() in [ "no", "false" ]:
                        self.ipv6_rpfilter_enabled = False
                    if value.lower() in [ "yes", "true" ]:
                        self.ipv6_rpfilter_enabled = True
            if self.ipv6_rpfilter_enabled:
                log.debug1("IPv6 rpfilter is enabled")
            else:
                log.debug1("IPV6 rpfilter is disabled")

            if self._firewalld_conf.get("IndividualCalls"):
                value = self._firewalld_conf.get("IndividualCalls")
                if value is not None and value.lower() in [ "yes", "true" ]:
                    log.debug1("IndividualCalls is enabled")
                    self._individual_calls = True

            if self._firewalld_conf.get("LogDenied"):
                value = self._firewalld_conf.get("LogDenied")
                if value is None or value.lower() == "no":
                    self._log_denied = "off"
                else:
                    self._log_denied = value.lower()
                    log.debug1("LogDenied is set to '%s'", self._log_denied)

            if self._firewalld_conf.get("AutomaticHelpers"):
                value = self._firewalld_conf.get("AutomaticHelpers")
                if value is not None:
                    if value.lower() in [ "no", "false" ]:
                        self._automatic_helpers = "no"
                    elif value.lower() in [ "yes", "true" ]:
                        self._automatic_helpers = "yes"
                    else:
                        self._automatic_helpers = value.lower()
                    log.debug1("AutomaticHelpers is set to '%s'",
                               self._automatic_helpers)

        self.config.set_firewalld_conf(copy.deepcopy(self._firewalld_conf))

        self._start_check()

        # load lockdown whitelist
        log.debug1("Loading lockdown whitelist")
        try:
            self.policies.lockdown_whitelist.read()
        except Exception as msg:
            if self.policies.query_lockdown():
                log.error("Failed to load lockdown whitelist '%s': %s",
                          self.policies.lockdown_whitelist.filename, msg)
            else:
                log.debug1("Failed to load lockdown whitelist '%s': %s",
                           self.policies.lockdown_whitelist.filename, msg)

        # copy policies to config interface
        self.config.set_policies(copy.deepcopy(self.policies))

        # load ipset files
        self._loader(config.FIREWALLD_IPSETS, "ipset")
        self._loader(config.ETC_FIREWALLD_IPSETS, "ipset")

        # load icmptype files
        self._loader(config.FIREWALLD_ICMPTYPES, "icmptype")
        self._loader(config.ETC_FIREWALLD_ICMPTYPES, "icmptype")

        if len(self.icmptype.get_icmptypes()) == 0:
            log.error("No icmptypes found.")

        # load helper files
        self._loader(config.FIREWALLD_HELPERS, "helper")
        self._loader(config.ETC_FIREWALLD_HELPERS, "helper")

        # load service files
        self._loader(config.FIREWALLD_SERVICES, "service")
        self._loader(config.ETC_FIREWALLD_SERVICES, "service")

        if len(self.service.get_services()) == 0:
            log.error("No services found.")

        # load zone files
        self._loader(config.FIREWALLD_ZONES, "zone")
        self._loader(config.ETC_FIREWALLD_ZONES, "zone")

        if len(self.zone.get_zones()) == 0:
            log.fatal("No zones found.")
            sys.exit(1)

        # check minimum required zones
        error = False
        for z in [ "block", "drop", "trusted" ]:
            if z not in self.zone.get_zones():
                log.fatal("Zone '%s' is not available.", z)
                error = True
        if error:
            sys.exit(1)

        # check if default_zone is a valid zone
        if default_zone not in self.zone.get_zones():
            if "public" in self.zone.get_zones():
                zone = "public"
            elif "external" in self.zone.get_zones():
                zone = "external"
            else:
                zone = "block" # block is a base zone, therefore it has to exist

            log.error("Default zone '%s' is not valid. Using '%s'.",
                      default_zone, zone)
            default_zone = zone
        else:
            log.debug1("Using default zone '%s'", default_zone)

        # load direct rules
        obj = Direct(config.FIREWALLD_DIRECT)
        if os.path.exists(config.FIREWALLD_DIRECT):
            log.debug1("Loading direct rules file '%s'" % \
                       config.FIREWALLD_DIRECT)
            try:
                obj.read()
            except Exception as msg:
                log.debug1("Failed to load direct rules file '%s': %s",
                           config.FIREWALLD_DIRECT, msg)
        self.direct.set_permanent_config(obj)
        self.config.set_direct(copy.deepcopy(obj))

        # automatic helpers
        if self._automatic_helpers != "system":
            functions.set_nf_conntrack_helper_setting(self._automatic_helpers == "yes")
        self.nf_conntrack_helper_setting = \
            functions.get_nf_conntrack_helper_setting()

        # check if needed tables are there
        self._check_tables()

        if log.getDebugLogLevel() > 0:
            # get time before flushing and applying
            tm1 = time.time()

        # Start transaction
        transaction = FirewallTransaction(self)

        if reload:
            self.set_policy("DROP", use_transaction=transaction)

        # flush rules
        self.flush(use_transaction=transaction)

        # If modules need to be unloaded in complete reload or if there are
        # ipsets to get applied, limit the transaction to set_policy and flush.
        #
        # Future optimization for the ipset case in reload: The transaction
        # only needs to be split here if there are conflicting ipset types in
        # exsting ipsets and the configuration in firewalld.
        if (reload and complete_reload) or \
           (self.ipset_enabled and self.ipset.has_ipsets()):
            transaction.execute(True)
            transaction.clear()

        # complete reload: unload modules also
        if reload and complete_reload:
            log.debug1("Unloading firewall modules")
            self.modules_backend.unload_firewall_modules()

        # apply settings for loaded ipsets while reloading here
        if self.ipset_enabled and self.ipset.has_ipsets():
            log.debug1("Applying ipsets")
            self.ipset.apply_ipsets()

        # Start or continue with transaction

        # apply default rules
        log.debug1("Applying default rule set")
        self.apply_default_rules(use_transaction=transaction)

        # apply settings for loaded zones
        log.debug1("Applying used zones")
        self.zone.apply_zones(use_transaction=transaction)

        self._default_zone = self.check_zone(default_zone)
        self.zone.change_default_zone(None, self._default_zone,
                                      use_transaction=transaction)

        # Execute transaction
        transaction.execute(True)

        # Start new transaction for direct rules
        transaction.clear()

        # apply direct chains, rules and passthrough rules
        if self.direct.has_configuration():
            transaction.enable_generous_mode()
            log.debug1("Applying direct chains rules and passthrough rules")
            self.direct.apply_direct(transaction)

            # Execute transaction
            transaction.execute(True)
            transaction.disable_generous_mode()
            transaction.clear()

        del transaction

        if log.getDebugLogLevel() > 1:
            # get time after flushing and applying
            tm2 = time.time()
            log.debug2("Flushing and applying took %f seconds" % (tm2 - tm1))

        self._state = "RUNNING"
Example #58
0
    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.error('Invalid rule: More than one element, ignoring.')
                    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"])
        elif name == "port":
            if self._rule:
                if self._rule.element:
                    log.error('Invalid rule: More than one element, ignoring.')
                    self._rule_error = True
                    return
                self._rule.element = Rich_Port(attrs["port"],
                                               attrs["protocol"])
                return
            # TODO: fix port string according to fw_zone.__port_id()
            entry = (attrs["port"], attrs["protocol"])
            if entry not in self.item.ports:
                self.item.ports.append(entry)
        elif name == "protocol":
            if self._rule:
                if self._rule.element:
                    log.error('Invalid rule: More than one element, ignoring.')
                    self._rule_error = True
                    return
                self._rule.element = Rich_Protocol(attrs["value"])
            else:
                log.error('Protocol allowed only in rule.')
            if attrs["value"] not in self.item.protocols:
                self.item.protocols.append(attrs["value"])
        elif name == "icmp-block":
            if self._rule:
                if self._rule.element:
                    log.error('Invalid rule: More than one element, ignoring.')
                    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"])
        elif name == "masquerade":
            if "enabled" in attrs:
                log.warning("Ignoring deprecated attribute enabled='%s'" %
                            attrs["enabled"])
            if self._rule:
                if self._rule.element:
                    log.error('Invalid rule: More than one element, ignoring.')
                    self._rule_error = True
                    return
                self._rule.element = Rich_Masquerade()
            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.error('Invalid rule: More than one element, ignoring.')
                    self._rule_error = True
                    return
                self._rule.element = Rich_ForwardPort(attrs["port"],
                                                      attrs["protocol"],
                                                      to_port, to_addr)
                return
            # TODO: fix port string according to fw_zone.__forward_port_id()
            entry = (attrs["port"], attrs["protocol"], to_port,
                     to_addr)
            if entry not in self.item.forward_ports:
                self.item.forward_ports.append(entry)

        elif name == "interface":
            if self._rule:
                log.error('Invalid rule: interface use in rule.')
                self._rule_error = True
                return
            # zone bound to interface
            if "name" not in attrs:
                log.error('Invalid interface: Name missing.')
                self._rule_error = True
                return
            name = attrs["name"]
            if name not in self.item.interfaces:
                self.item.interfaces.append(name)
            
        elif name == "source":
            if self._rule:
                if self._rule.source:
                    log.error('Invalid rule: More than one source')
                    self._rule_error = True
                    return
                invert = False
                if "invert" in attrs and \
                        attrs["invert"].lower() in [ "yes", "true" ]:
                    invert = True
                self._rule.source = Rich_Source(attrs["address"], invert)
                return
            # zone bound to source
            if "address" not in attrs:
                log.error('Invalid source: Address missing.')
                return
            if "family" in attrs:
                log.warning("Ignoring deprecated attribute family='%s'" %
                            attrs["family"])
            if "invert" in attrs:
                log.error('Invalid source: Invertion not allowed here.')
                return
            entry = attrs["address"]
            if entry not in self.item.sources:
                self.item.sources.append(entry)

        elif name == "destination":
            if not self._rule:
                log.error('Invalid rule: Destination outside of rule')
                self._rule_error = True
                return
            if self._rule.destination:
                log.error('Invalid rule: More than one destination')
                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" ]:
            if not self._rule:
                log.error('Invalid rule: Action outside of rule')
                self._rule_error = True
                return
            if self._rule.action:
                log.error('Invalid rule: More than one action')
                self._rule_error = True
                return
            if name == "accept":
                self._rule.action = Rich_Accept()
            if name == "reject":
                _type = None
                if "type" in attrs:
                    _type = attrs["type"]
                self._rule.action = Rich_Reject(_type)
            if name == "drop":
                self._rule.action = Rich_Drop()
            self._limit_ok = self._rule.action

        elif name == "log":
            if not self._rule:
                log.error('Invalid rule: Log outside of rule')
                return
            if self._rule.log:
                log.error('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.error('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.error('Invalid rule: Audit outside of rule')
                return
            if self._rule.audit:
                log.error('Invalid rule: More than one audit')
                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.error('Invalid rule: Rule family "%s" invalid' % 
                              attrs["family"])
                    self._rule_error = True
                    return
            self._rule = Rich_Rule(family)
            self.item.rules.append(self._rule)

        elif name == "limit":
            if not self._limit_ok:
                log.error('Invalid rule: Limit outside of action, log and audit')
                self._rule_error = True
                return
            if self._limit_ok.limit:
                log.error('Invalid rule: More than one limit')
                self._rule_error = True
                return
            value = attrs["value"]
            self._limit_ok.limit = Rich_Limit(value)

        else:
            log.error('Unknown XML element %s' % name)
            return