diff --git a/README.md b/README.md
index 43fe65b8b9cc737faf5a25dcdd097b332ac91ec0..c429494ea17b15672aee0766fcdfae0e29aab3b7 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[PACKAGE]: ../../raw/master/mkp/unbound-1.2.6-20240527.mkp "unbound-1.2.6-20240527.mkp"
+[PACKAGE]: ../../raw/master/mkp/unbound-1.3.3-20240927.mkp "unbound-1.3.3-20240927.mkp"
 # unbound
 
 This agent plugin cheks the state of the unbound dns daemon. For more information about unbound see: https://nlnetlabs.nl/projects/unbound/about/
diff --git a/mkp/unbound-1.3.3-20240927.mkp b/mkp/unbound-1.3.3-20240927.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..653151d6d9584aa7a2777cf0180da4cbf9dec470
Binary files /dev/null and b/mkp/unbound-1.3.3-20240927.mkp differ
diff --git a/source/agent_based/unbound.py b/source/agent_based/unbound.py
index f37ffe99ea98d53aaaa79fbc2eaab1b298899faa..879ebd399304409f338670561a7f5b52ae74775b 100644
--- a/source/agent_based/unbound.py
+++ b/source/agent_based/unbound.py
@@ -25,37 +25,11 @@
 #             added output in case get_rate is initialising (unknown state in discovery)
 #             removed default levels for unbound_answers
 #             added params for unwanted replies
+# 2024-07-24: split unbound.py in separate files per check
 
-
-from time import time as now_time
-from typing import (
-    Any,
-    Mapping,
-)
-
-from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
-    CheckResult,
-    DiscoveryResult,
-    StringTable,
-)
-
-from cmk.base.plugins.agent_based.agent_based_api.v1 import (
-    GetRateError,
-    Result,
-    Service,
-    State,
-    check_levels,
-    get_rate,
-    get_value_store,
-    register,
-    render,
-)
-
-UnboundSection = Mapping[str, int | float]
-
-
-def render_qps(x: float) -> str:
-    return f'{x:.2f}/s'
+from cmk.base.plugins.agent_based.agent_based_api.v1 import register
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import StringTable
+from cmk.base.plugins.agent_based.utils.unbound import UnboundSection
 
 
 def parse_unbound(string_table: StringTable) -> UnboundSection:
@@ -65,6 +39,7 @@ def parse_unbound(string_table: StringTable) -> UnboundSection:
             section[key] = int(value)
         except ValueError:
             section[key] = float(value)
+
     return section
 
 
@@ -72,175 +47,3 @@ register.agent_section(
     name='unbound',
     parse_function=parse_unbound,
 )
-
-
-def discover_unbound_cache(section: UnboundSection) -> DiscoveryResult:
-    if 'total.num.cachehits' in section and 'total.num.cachemiss' in section:
-        yield Service()
-
-
-def check_unbound_cache(
-        params: Mapping[str, Any],
-        section: UnboundSection,
-) -> CheckResult:
-    cumulative_cache_hits = section.get('total.num.cachehits')
-    cumulative_cache_miss = section.get('total.num.cachemiss')
-    now = now_time()
-
-    if None in (cumulative_cache_hits, cumulative_cache_miss, now):
-        return
-
-    cache_hits = get_rate(
-        get_value_store(),
-        'unbound_cache_hits',
-        now,
-        cumulative_cache_hits,
-        raise_overflow=True,
-    )
-    cache_miss = get_rate(
-        get_value_store(),
-        'unbound_cache_miss',
-        now,
-        cumulative_cache_miss,
-        raise_overflow=True,
-    )
-    total = cache_hits + cache_miss
-    hit_perc = (cache_hits / float(total)) * 100.0 if total != 0 else 100.0
-
-    yield from check_levels(
-        value=cache_miss,
-        metric_name='cache_misses_rate',
-        levels_upper=params.get('cache_misses'),
-        render_func=render_qps,
-        label='Cache Misses',
-        notice_only=True,
-    )
-
-    yield from check_levels(
-        value=cache_hits,
-        metric_name='cache_hit_rate',
-        render_func=render_qps,
-        label='Cache Hits',
-        notice_only=True,
-    )
-
-    yield from check_levels(
-        value=hit_perc,
-        metric_name='cache_hit_ratio',
-        levels_lower=params.get('cache_hits'),
-        render_func=render.percent,
-        label='Cache Hit Ratio',
-    )
-
-
-register.check_plugin(
-    name='unbound_cache',
-    service_name='Unbound Cache',
-    sections=['unbound'],
-    discovery_function=discover_unbound_cache,
-    check_function=check_unbound_cache,
-    check_default_parameters={},
-    check_ruleset_name='unbound_cache',
-)
-
-
-def discover_unbound_answers(section: UnboundSection) -> DiscoveryResult:
-    if 'num.answer.rcode.SERVFAIL' in section:
-        yield Service()
-
-
-def check_unbound_answers(params: Mapping, section: UnboundSection) -> CheckResult:
-    key_prefix = 'num.answer.rcode.'
-    now = now_time()
-
-    total = sum(
-        value for key, value in section.items()
-        if key.startswith(key_prefix)
-    )
-
-    init_counters = False
-    for key, value in section.items():
-        if not key.startswith(key_prefix):
-            continue
-        answer = key[len(key_prefix):]
-
-        try:
-            rate = get_rate(
-                get_value_store(),
-                f'unbound_answers_{answer}',
-                now,
-                value,
-                raise_overflow=True,
-            )
-        except GetRateError as e:
-            if not init_counters:
-                yield Result(state=State.OK, summary=str(e))
-                init_counters = True
-        else:
-            levels_upper = params.get(f'levels_upper_{answer}')
-            if levels_upper is not None and len(levels_upper) == 3:
-                # levels on the ratio of answers
-                levels_upper = (
-                    levels_upper[0] * total,
-                    levels_upper[1] * total,
-                )
-            yield from check_levels(
-                value=rate,
-                levels_upper=levels_upper,
-                metric_name=f'unbound_answers_{answer}',
-                render_func=render_qps,
-                label=answer,
-                notice_only=f'levels_upper_{answer}' not in params,
-            )
-
-
-register.check_plugin(
-    name='unbound_answers',
-    service_name='Unbound Answers',
-    sections=['unbound'],
-    discovery_function=discover_unbound_answers,
-    check_function=check_unbound_answers,
-    check_default_parameters={
-        # 'levels_upper_NOERROR': (101, 101),
-        # 'levels_upper_SERVFAIL': (10, 100),
-        # 'levels_upper_REFUSED': (10, 100),
-    },
-    check_ruleset_name='unbound_answers',
-)
-
-
-def discover_unbound_unwanted_replies(section: UnboundSection) -> DiscoveryResult:
-    if 'unwanted.replies' in section:
-        yield Service()
-
-
-def check_unbound_unwanted_replies(params, section: UnboundSection) -> CheckResult:
-    if 'unwanted.replies' not in section:
-        return
-
-    rate = get_rate(
-        get_value_store(),
-        'unbound_unwanted_replies',
-        now_time(),
-        section['unwanted.replies'],
-        raise_overflow=True,
-    )
-
-    yield from check_levels(
-        value=rate,
-        levels_upper=params.get('unwanted_replies'),
-        metric_name='unbound_unwanted_replies',
-        render_func=render_qps,
-        label='Unwanted Replies',
-    )
-
-
-register.check_plugin(
-    name='unbound_unwanted_replies',
-    service_name='Unbound Unwanted Replies',
-    sections=['unbound'],
-    discovery_function=discover_unbound_unwanted_replies,
-    check_function=check_unbound_unwanted_replies,
-    check_default_parameters={},
-    check_ruleset_name='unbound_replies',
-)
diff --git a/source/agent_based/unbound_answers.py b/source/agent_based/unbound_answers.py
new file mode 100644
index 0000000000000000000000000000000000000000..09b5366c02840db6e51a9a428a11adbcc87725ab
--- /dev/null
+++ b/source/agent_based/unbound_answers.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2022, Jan-Philipp Litza (PLUTEX) <jpl@plutex.de>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# https://nlnetlabs.nl/projects/unbound/about/
+
+# changes by thl-cmk[at]outlook[dot]com
+# 2024-04-21: removed Union -> no need "int | float" should do
+#             added levels_upper_NOERROR to default parameters -> show up in info line
+# 2024-05-22: changed time for get_rate from section to system time
+#             added output in case get_rate is initialising (unknown state in discovery)
+#             removed default levels for unbound_answers
+#             added params for unwanted replies
+
+
+from time import time as now_time
+from typing import (
+    Mapping,
+)
+
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    CheckResult,
+    DiscoveryResult,
+)
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    GetRateError,
+    Result,
+    Service,
+    State,
+    check_levels,
+    get_rate,
+    get_value_store,
+    register,
+)
+
+from cmk.base.plugins.agent_based.utils.unbound import (
+    UnboundSection,
+    render_qps,
+)
+
+
+def discover_unbound_answers(section: UnboundSection) -> DiscoveryResult:
+    if 'num.answer.rcode.SERVFAIL' in section:
+        yield Service()
+
+
+def check_unbound_answers(params: Mapping, section: UnboundSection) -> CheckResult:
+    key_prefix = 'num.answer.rcode.'
+    now = now_time()
+
+    total = sum(
+        value for key, value in section.items()
+        if key.startswith(key_prefix)
+    )
+
+    init_counters = False
+    for key, value in section.items():
+        if not key.startswith(key_prefix):
+            continue
+        answer = key[len(key_prefix):]
+
+        try:
+            rate = get_rate(
+                get_value_store(),
+                f'unbound_answers_{answer}',
+                now,
+                value,
+                raise_overflow=True,
+            )
+        except GetRateError as e:
+            if not init_counters:
+                yield Result(state=State.OK, summary=str(e))
+                init_counters = True
+        else:
+            levels_upper = params.get(f'levels_upper_{answer}')
+            if levels_upper is not None and len(levels_upper) == 3:
+                # levels on the ratio of answers
+                levels_upper = (
+                    levels_upper[0] * total,
+                    levels_upper[1] * total,
+                )
+            yield from check_levels(
+                value=rate,
+                levels_upper=levels_upper,
+                metric_name=f'unbound_answers_{answer}',
+                render_func=render_qps,
+                label=answer,
+                notice_only=f'levels_upper_{answer}' not in params,
+            )
+
+
+register.check_plugin(
+    name='unbound_answers',
+    service_name='Unbound Answers',
+    sections=['unbound'],
+    discovery_function=discover_unbound_answers,
+    check_function=check_unbound_answers,
+    check_default_parameters={
+        # 'levels_upper_NOERROR': (101, 101),
+        # 'levels_upper_SERVFAIL': (10, 100),
+        # 'levels_upper_REFUSED': (10, 100),
+    },
+    check_ruleset_name='unbound_answers',
+)
diff --git a/source/agent_based/unbound_cache.py b/source/agent_based/unbound_cache.py
new file mode 100644
index 0000000000000000000000000000000000000000..995cee3018c55324ba41271c1d87ef6304c5606a
--- /dev/null
+++ b/source/agent_based/unbound_cache.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2022, Jan-Philipp Litza (PLUTEX) <jpl@plutex.de>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# https://nlnetlabs.nl/projects/unbound/about/
+
+# changes by thl-cmk[at]outlook[dot]com
+# 2024-04-21: removed Union -> no need "int | float" should do
+#             added levels_upper_NOERROR to default parameters -> show up in info line
+# 2024-05-22: changed time for get_rate from section to system time
+#             added output in case get_rate is initialising (unknown state in discovery)
+#             removed default levels for unbound_answers
+#             added params for unwanted replies
+
+
+from time import time as now_time
+from typing import (
+    Any,
+    Mapping,
+)
+
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    CheckResult,
+    DiscoveryResult,
+)
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    Service,
+    check_levels,
+    get_rate,
+    get_value_store,
+    register,
+    render,
+)
+
+from cmk.base.plugins.agent_based.utils.unbound import (
+    UnboundSection,
+    render_qps,
+)
+
+
+def discover_unbound_cache(section: UnboundSection) -> DiscoveryResult:
+    if 'total.num.cachehits' in section and 'total.num.cachemiss' in section:
+        yield Service()
+
+
+def check_unbound_cache(
+        params: Mapping[str, Any],
+        section: UnboundSection,
+) -> CheckResult:
+    cumulative_cache_hits = section.get('total.num.cachehits')
+    cumulative_cache_miss = section.get('total.num.cachemiss')
+    now = now_time()
+
+    if None in (cumulative_cache_hits, cumulative_cache_miss, now):
+        return
+
+    cache_hits = get_rate(
+        get_value_store(),
+        'unbound_cache_hits',
+        now,
+        cumulative_cache_hits,
+        raise_overflow=True,
+    )
+    cache_miss = get_rate(
+        get_value_store(),
+        'unbound_cache_miss',
+        now,
+        cumulative_cache_miss,
+        raise_overflow=True,
+    )
+    total = cache_hits + cache_miss
+    hit_perc = (cache_hits / float(total)) * 100.0 if total != 0 else 100.0
+
+    yield from check_levels(
+        value=cache_miss,
+        metric_name='cache_misses_rate',
+        levels_upper=params.get('cache_misses'),
+        render_func=render_qps,
+        label='Cache Misses',
+        notice_only=True,
+    )
+
+    yield from check_levels(
+        value=cache_hits,
+        metric_name='cache_hit_rate',
+        render_func=render_qps,
+        label='Cache Hits',
+        notice_only=True,
+    )
+
+    yield from check_levels(
+        value=hit_perc,
+        metric_name='cache_hit_ratio',
+        levels_lower=params.get('cache_hits'),
+        render_func=render.percent,
+        label='Cache Hit Ratio',
+    )
+
+
+register.check_plugin(
+    name='unbound_cache',
+    service_name='Unbound Cache',
+    sections=['unbound'],
+    discovery_function=discover_unbound_cache,
+    check_function=check_unbound_cache,
+    check_default_parameters={},
+    check_ruleset_name='unbound_cache',
+)
+
diff --git a/source/agent_based/unbound_status.py b/source/agent_based/unbound_status.py
index 3cc99411c5bb5998be6010e5d18c45ee2326067b..08d89ef018547d1311bfcd673af01c6d639d934b 100644
--- a/source/agent_based/unbound_status.py
+++ b/source/agent_based/unbound_status.py
@@ -8,13 +8,12 @@
 # Date  : 2024-05-21
 # File  : unbound_status.py
 
-from dataclasses import dataclass
+# 2024-09-10: fixed crash if unbound is not running
 
-from typing import (
-    Any,
-    Mapping,
-    Sequence
-)
+from collections.abc import Mapping, Sequence
+from dataclasses import dataclass
+from re import match as re_match
+from typing import Any
 
 from cmk.utils import debug
 from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
@@ -24,28 +23,38 @@ from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
 )
 
 from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    Result,
     Service,
+    State,
     check_levels,
     register,
     render,
-    Result,
-    State,
 )
 
 
 @dataclass(frozen=True)
 class UnboundStatus:
-    version: str
-    verbosity: int
-    threads: int
-    modules: Sequence[str]
-    uptime: int
-    options: Sequence[str]
     status: str
-    pid: int
+    modules: Sequence[str] | None = None
+    options: Sequence[str] | None = None
+    pid: int | None = None
+    threads: int | None = None
+    uptime: int | None = None
+    verbosity: int | None = None
+    version: str | None = None
 
     @classmethod
     def parse(cls, string_table: StringTable):
+        # set defaults
+        modules = None
+        options = None
+        pid = None
+        status = None
+        threads = None
+        uptime = None
+        verbosity = None
+        version = None
+
         for line in string_table:
             key, value = line[0].split(' ', 1)
             key = key.rstrip(':')
@@ -67,25 +76,30 @@ class UnboundStatus:
                     options = value.split(' ')
                 case 'unbound':
                     # (pid 520) is running...
-                    pid = int(value.split(') ')[0].replace('(pid ', ''))
-                    status = value.split(') ', -1)[-1].strip('.')
+                    # is stopped
+                    re_pid = r'\(pid (\d+)\).*'
+                    re_status = r'.*(is \w+)'
+                    if pid := re_match(re_pid, value):
+                        pid = pid[1]
+                    if status := re_match(re_status, value):
+                        status = status[1]
                 case _:
                     pass
 
         try:
             return cls(
-                version=version,
-                verbosity=verbosity,
-                threads=threads,
                 modules=modules,
-                uptime=uptime,
                 options=options,
                 pid=pid,
                 status=status,
+                threads=threads,
+                uptime=uptime,
+                verbosity=verbosity,
+                version=version,
             )
         except NameError as e:
             if debug.enabled:
-                print(f'name error {e}')
+                print(f'name error: {e}')
             return
 
 
@@ -100,20 +114,25 @@ register.agent_section(
 
 
 def discover_unbound_status(section: UnboundStatus) -> DiscoveryResult:
+    print(section)
     yield Service()
 
 
 # UnboundStatus(
-#     version='1.13.1',
-#     verbosity=0,
-#     threads=1,
 #     modules=['subnet', 'validator', 'iterator'],
-#     uptime=1759,
 #     options=['reuseport', 'control(ssl)'],
-#     status='(pid 520) is running',
 #     pid=520
+#     status='(pid 520) is running',
+#     threads=1,
+#     uptime=1759,
+#     verbosity=0,
+#     version='1.13.1',
 # )
 def check_unbound_status(params: Mapping[str, Any], section: UnboundStatus, ) -> CheckResult:
+    if section.status != 'is running':
+        yield Result(state=State(params['status_not_running']), summary=f'Status: {section.status}')
+        return
+
     yield Result(state=State.OK, summary=f'Status: {section.status}')
     yield from check_levels(
         value=section.uptime,
@@ -129,6 +148,8 @@ register.check_plugin(
     service_name="Unbound",
     discovery_function=discover_unbound_status,
     check_function=check_unbound_status,
-    check_default_parameters={},
+    check_default_parameters={
+        'status_not_running': 2
+    },
     check_ruleset_name="unbound_status",
 )
diff --git a/source/agent_based/unbound_type_stats.py b/source/agent_based/unbound_type_stats.py
new file mode 100644
index 0000000000000000000000000000000000000000..2e3af1b60f92d22b0f83c2ac310c128bd9f014fc
--- /dev/null
+++ b/source/agent_based/unbound_type_stats.py
@@ -0,0 +1,289 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2024-05-21
+# File  : unbound_type_stats.py
+
+# based on the unbound plugin by Jan-Philipp Litza (PLUTEX) <jpl@plutex.de>.
+# and the work of ruettimann[at]init7[dot]net
+
+# https://nlnetlabs.nl/projects/unbound/about/
+
+from collections.abc import Mapping, Sequence, MutableSequence
+from time import time as now_time
+from typing import (
+    List,
+    Tuple,
+)
+
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    CheckResult,
+    DiscoveryResult,
+)
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    GetRateError,
+    Result,
+    Service,
+    State,
+    check_levels,
+    get_rate,
+    get_value_store,
+    register,
+)
+
+from cmk.base.plugins.agent_based.utils.unbound import (
+    UnboundSection,
+    render_qps,
+)
+
+# https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
+ANSWER_TYPES_MOST_COMMON: List[str] = [
+    'A',
+    'AAAA',
+    'ANY',
+    'CNAME',
+    'DNSKEY',
+    'DS',
+    'HINFO',
+    'HTTPS',
+    'MX',
+    'NAPTR',
+    'NS',
+    'PTR',
+    'RRSIG',
+    'SOA',
+    'SRV',
+    'SVCB',
+    'TXT',
+    # 'TYPE65',  # in summary for HTTPS
+]
+ANSWER_TYPES_COMMON: List[str] = [
+    'AFSDB',
+    'APL',
+    'CAA',
+    'CDNSKEY',
+    'CDS',
+    'CERT',
+    'CSYNC',
+    'DHCID',
+    'DLV',
+    'DNAME',
+    'EUI48',
+    'EUI64',
+    'HIP',
+    'IPSECKEY',
+    'KEY',
+    'KX',
+    'LOC',
+    'NSEC',
+    'NSEC3',
+    'NSEC3PARAM',
+    'OPENPGPKEY',
+    'RP',
+    'SIG',
+    'SMIMEA',
+    'SSHFP',
+    'TA',
+    'TKEY',
+    'TLSA',
+    'TSIG',
+    'URI',
+    'WALLET',
+    'ZONEMD',
+]
+ANSWER_TYPES_OBSOLETE: List[str] = [
+    'A6',
+    'ATMA',
+    'DOA',
+    'EID',
+    'GID',
+    'GPOS',
+    'ISDN',
+    'L32',
+    'L64',
+    'LP',
+    'MAILA',
+    'MAILB',
+    'MB',
+    'MD',
+    'MF',
+    'MG',
+    'MINFO',
+    'MR',
+    'NB',
+    'NBSTAT',
+    'NID',
+    'NIMLOC',
+    'NINFO',
+    'NSAP',
+    'NSAP-PTR',
+    'NULL',
+    'NXT',
+    'PX',
+    'RKEY',
+    'RT',
+    'SINK',
+    'SPF',
+    'TALINK',
+    'UID',
+    'UINFO',
+    'UNSPEC',
+    'WKS',
+    'X25',
+]
+
+ANSWER_TYPES: List[str] = ANSWER_TYPES_MOST_COMMON + ANSWER_TYPES_COMMON + ANSWER_TYPES_OBSOLETE
+
+SUM_TYPES: Mapping[str: Sequence[str]] = {
+    'AAAA': ['AAAA', 'A6'],
+    'HTTPS': ['HTTPS', 'TYPE65'],
+}
+
+
+def discover_unbound_type_stats(section: UnboundSection) -> DiscoveryResult:
+    if 'num.query.type.A' in section:
+        yield Service()
+
+
+def yield_answer(
+        answer: str,
+        levels_upper: Tuple[int, int] | None,
+        total: float,
+        value: float,
+        notice: bool = True,
+        metric: bool = True,
+):
+    now = now_time()
+    try:
+        rate = get_rate(
+            get_value_store(),
+            f'unbound_type_stats_{answer}',
+            now,
+            value,
+            raise_overflow=True,
+        )
+    except GetRateError as e:
+        yield Result(state=State.OK, notice=str(e))
+        return
+    else:
+        # if rate == 0:
+        #     return
+        if levels_upper is not None and len(levels_upper) == 3:
+            # levels on the ratio of answers
+            levels_upper = (
+                levels_upper[0] * total,
+                levels_upper[1] * total,
+            )
+        # if levels_upper:
+        #     notice = False
+        metric_name = f'unbound_type_stats_{answer.replace("-", "_").replace(" ", "_")}' if metric else None
+        yield from check_levels(
+            value=rate,
+            levels_upper=levels_upper,
+            metric_name=metric_name,
+            render_func=render_qps,
+            label=answer,
+            notice_only=notice,
+        )
+
+
+# ToDo: values are converted to answers/s, total is an absolute value -> should be changed to rate/1?
+def check_unbound_type_stats(params: Mapping, section: UnboundSection) -> CheckResult:
+    key_prefix = 'num.query.type.'
+    total_common: float = 0.0
+    total_obsolete: float = 0.0
+    other_value: float = 0.0
+    other_types_found: MutableSequence[str] = []
+
+    for sum_type in SUM_TYPES:
+        summary = 0.0
+        for answer_type in SUM_TYPES[sum_type]:
+            key = f'{key_prefix}{answer_type}'
+            summary += section.get(key, 0.0)
+            try:
+                section.pop(key)
+            except KeyError:
+                pass
+
+        if summary > 0.0:
+            section.update({f'{key_prefix}{sum_type}': summary})
+
+    section = dict(sorted(section.items()))
+
+    total = sum(
+        value for key, value in section.items()
+        if key.startswith(key_prefix)
+    )
+
+    for key, value in section.items():
+        if not key.startswith(key_prefix):
+            continue
+        answer = key[len(key_prefix):]
+
+        if answer in ANSWER_TYPES:
+            if answer in ANSWER_TYPES_COMMON:
+                total_common += value
+            elif answer in ANSWER_TYPES_OBSOLETE:  #
+                total_obsolete += value
+
+            yield from yield_answer(
+                answer=answer,
+                total=total,
+                value=value,
+                levels_upper=params.get(f'levels_upper_{answer}')
+            )
+        else:
+            other_types_found.append(answer)
+            other_value += value
+            yield from yield_answer(
+                answer=answer,
+                total=total,
+                value=value,
+                levels_upper=None,
+                metric=False,
+            )
+
+    if other_types_found:
+        answer = 'others'
+        yield from yield_answer(
+            answer=answer,
+            total=total,
+            value=other_value,
+            levels_upper=params.get(f'levels_upper_{answer}')
+        )
+        answer_types = ', '.join(other_types_found)
+        yield Result(
+            state=State(params.get('state_other_type', 0)),
+            notice=f'Other DNS answer typ(e) found: {answer_types}'
+        )
+
+    for answer, value in [
+        ('Total', total),
+        ('Total_common', total_common),
+        ('Total_obsolete', total_obsolete),
+    ]:
+        if value > 0:
+            yield from yield_answer(
+                answer=answer,
+                total=total,
+                value=value,
+                levels_upper=params.get(f'levels_upper_{answer}'),
+                notice=False,
+            )
+
+
+register.check_plugin(
+    name='unbound_type_stats',
+    service_name='Unbound Type Stats',
+    sections=['unbound'],
+    discovery_function=discover_unbound_type_stats,
+    check_function=check_unbound_type_stats,
+    check_default_parameters={
+    },
+    check_ruleset_name='unbound_type_stats',
+)
diff --git a/source/agent_based/unbound_unwanted_replies.py b/source/agent_based/unbound_unwanted_replies.py
new file mode 100644
index 0000000000000000000000000000000000000000..2c9b207c966a328f728706772331f7fb39627472
--- /dev/null
+++ b/source/agent_based/unbound_unwanted_replies.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2022, Jan-Philipp Litza (PLUTEX) <jpl@plutex.de>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# https://nlnetlabs.nl/projects/unbound/about/
+
+# changes by thl-cmk[at]outlook[dot]com
+# 2024-04-21: removed Union -> no need "int | float" should do
+#             added levels_upper_NOERROR to default parameters -> show up in info line
+# 2024-05-22: changed time for get_rate from section to system time
+#             added output in case get_rate is initialising (unknown state in discovery)
+#             removed default levels for unbound_answers
+#             added params for unwanted replies
+
+
+from time import time as now_time
+
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    CheckResult,
+    DiscoveryResult,
+)
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    Service,
+    check_levels,
+    get_rate,
+    get_value_store,
+    register,
+)
+
+from cmk.base.plugins.agent_based.utils.unbound import (
+    UnboundSection,
+    render_qps,
+)
+
+
+def discover_unbound_unwanted_replies(section: UnboundSection) -> DiscoveryResult:
+    if 'unwanted.replies' in section:
+        yield Service()
+
+
+def check_unbound_unwanted_replies(params, section: UnboundSection) -> CheckResult:
+    if 'unwanted.replies' not in section:
+        return
+
+    rate = get_rate(
+        get_value_store(),
+        'unbound_unwanted_replies',
+        now_time(),
+        section['unwanted.replies'],
+        raise_overflow=True,
+    )
+
+    yield from check_levels(
+        value=rate,
+        levels_upper=params.get('unwanted_replies'),
+        metric_name='unbound_unwanted_replies',
+        render_func=render_qps,
+        label='Unwanted Replies',
+    )
+
+
+register.check_plugin(
+    name='unbound_unwanted_replies',
+    service_name='Unbound Unwanted Replies',
+    sections=['unbound'],
+    discovery_function=discover_unbound_unwanted_replies,
+    check_function=check_unbound_unwanted_replies,
+    check_default_parameters={},
+    check_ruleset_name='unbound_replies',
+)
diff --git a/source/agent_based/utils/unbound.py b/source/agent_based/utils/unbound.py
new file mode 100644
index 0000000000000000000000000000000000000000..4833a50e11f217cf5be55d096a4a8c1ce8a11cfc
--- /dev/null
+++ b/source/agent_based/utils/unbound.py
@@ -0,0 +1,17 @@
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2024-07-12
+# File  : plugins/agent_based/utils/unbound.py
+
+
+from collections.abc import MutableMapping
+
+UnboundSection = MutableMapping[str, int | float]
+
+
+def render_qps(x: float) -> str:
+    return f'{x:.2f}/s'
+
+
diff --git a/source/gui/metrics/unbound.py b/source/gui/metrics/unbound_answers.py
similarity index 77%
rename from source/gui/metrics/unbound.py
rename to source/gui/metrics/unbound_answers.py
index deec35d470fd1f93698eac4e257808afdf9fe597..a9bddfb07f78fc242039430791347e5c70900611 100644
--- a/source/gui/metrics/unbound.py
+++ b/source/gui/metrics/unbound_answers.py
@@ -77,7 +77,15 @@ graph_info['unbound_answers'] = {
     'title': _('Rate of answers'),
     'metrics': [
         (f'unbound_answers_{answer}', 'line')
-        for answer in ('NOERROR', 'FORMERR', 'SERVFAIL', 'NXDOMAIN', 'NOTIMPL', 'REFUSED', 'nodata')
+        for answer in (
+            'FORMERR',
+            'NOERROR',
+            'NOTIMPL',
+            'NXDOMAIN',
+            'REFUSED',
+            'SERVFAIL',
+            'nodata',
+        )
     ],
 }
 
@@ -95,32 +103,3 @@ perfometer_info.append(('stacked', [
         'exponent': 2,
     },
 ]))
-
-metric_info['cache_hit_rate'] = {
-    'title': _('Cache hits per second'),
-    'unit': '1/s',
-    'color': '26/a',
-}
-
-graph_info['cache_hit_misses'] = {
-    'title': _('Cache Hits and Misses'),
-    'metrics': [('cache_hit_rate', 'line'), ('cache_misses_rate', 'line')],
-}
-
-metric_info['unbound_unwanted_replies'] = {
-    'title': _('Unwanted replies'),
-    'unit': '1/s',
-    'color': '26/a',
-}
-
-graph_info['unbound_unwanted_replies'] = {
-    'title': _('Unwanted replies'),
-    'metrics': [('unbound_unwanted_replies', 'area')],
-}
-
-perfometer_info.append({
-    'type': 'logarithmic',
-    'metric': 'unbound_unwanted_replies',
-    'half_value': 100.0,  # ome year
-    'exponent': 2,
-})
diff --git a/source/gui/metrics/unbound_cache.py b/source/gui/metrics/unbound_cache.py
new file mode 100644
index 0000000000000000000000000000000000000000..d485617f600ef6e8062c7e66540586b5c0130101
--- /dev/null
+++ b/source/gui/metrics/unbound_cache.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+# -*- encoding: utf-8; py-indent-offset: 4 -*-
+
+# Copyright (C) 2022, Jan-Philipp Litza (PLUTEX) <jpl@plutex.de>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# modifications by thl-cmk[at]outlook[dot]com
+# 2024-02-21: changed import path form mk.gui.plugins.metrics to mk.gui.plugins.metrics.utils
+#             added metrics/graph for unbound_unwanted_replies
+#             moved to ~/local/lib/check_mk/gui/plugins/metrics (from local/share/check_mk/web/plugins/metrics)
+#             added perfometer for unbound_answers (NOERROR/SERVFAIL) and unbound_unwanted_replies
+
+from cmk.gui.i18n import _
+
+from cmk.gui.plugins.metrics.utils import (
+    metric_info,
+    graph_info,
+    perfometer_info,
+)
+
+metric_info['cache_hit_rate'] = {
+    'title': _('Cache hits per second'),
+    'unit': '1/s',
+    'color': '26/a',
+}
+
+graph_info['cache_hit_misses'] = {
+    'title': _('Cache Hits and Misses'),
+    'metrics': [
+        ('cache_hit_rate', 'line'),
+        ('cache_misses_rate', 'line'),
+    ],
+}
diff --git a/source/gui/metrics/unbound_type_stats.py b/source/gui/metrics/unbound_type_stats.py
new file mode 100644
index 0000000000000000000000000000000000000000..b28b17d6ce252d5dfc63e51fc9a6f1097c5f8ec5
--- /dev/null
+++ b/source/gui/metrics/unbound_type_stats.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2024-08-02
+# File  : unbound_type_stats.py
+
+# based on the work of ruettimann[at]init7[dot]net
+
+# https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
+
+# 2024-08-02: optimized answer_types and metrics creation
+# 2024-08-18: added common and obsolete answer types
+# 2024-08-27: removed duplicate answer types
+#             added METRIC_TYPE and ADD-TOTAL options
+
+from collections.abc import Mapping
+from typing import Final
+from cmk.gui.i18n import _
+
+from cmk.gui.plugins.metrics.utils import (
+    check_metrics,
+    graph_info,
+    metric_info,
+    perfometer_info,
+)
+
+METRIC_TYPE: Final[str] = 'stack'  # can be stack or line
+ADD_TOTAL: Final[bool] = True
+
+answer_types_most_common: Mapping[str, str] = {
+    'Total': '26/a',
+    'Total common': '26/b',
+    'Total obsolete': '16/b',
+    'A': '11/a',
+    'AAAA': '21/a',
+    'ANY': '31/a',
+    'CNAME': '41/a',
+    'DNSKEY': '12/a',
+    'DS': '22/a',
+    'HINFO': '24/a',
+    'HTTPS': '15/a',
+    'MX': '32/a',
+    'NAPTR': '42/a',
+    'NS': '13/a',
+    'PTR': '23/a',
+    'RRSIG': '34/a',
+    'SOA': '33/a',
+    'SRV': '43/a',
+    'SVCB': '44/a',
+    'TXT': '14/a',
+    'others': '36/a',
+}
+
+# https://en.wikipedia.org/wiki/List_of_DNS_record_types
+answer_types_common: Mapping[str, str] = {
+    'AFSDB': '11/a',
+    'APL': '12/a',
+    'CAA': '13/a',
+    'CDNSKEY': '14/a',
+    'CDS': '15/a',
+    'CERT': '16/a',
+    'CSYNC': '21/a',
+    'DHCID': '22/a',
+    'DLV': '23/a',
+    'DNAME': '24/a',
+    'EUI48': '25/a',
+    'EUI64': '31/a',
+    'HIP': '32/a',
+    'IPSECKEY': '33/a',
+    'KEY': '34/a',
+    'KX': '35/a',
+    'LOC': '36/a',
+    'NSEC': '42/a',
+    'NSEC3': '43/a',
+    'NSEC3PARAM': '44/a',
+    'OPENPGPKEY': '45/a',
+    'RP': '46/a',
+    'SIG': '11/b',
+    'SMIMEA': '12/b',
+    'SSHFP': '13/b',
+    'TA': '14/b',
+    'TKEY': '15/b',
+    'TLSA': '16/b',
+    'TSIG': '21/b',
+    'URI': '22/b',
+    'WALLET': '23/b',
+    'ZONEMD': '24/b',
+}
+
+# https://en.wikipedia.org/wiki/List_of_DNS_record_types
+answer_types_obsolete: Mapping[str, str] = {
+    'MD': '11/b',
+    'MF': '12/b',
+    'MAILA': '13/b',
+    'MB': '14/b',
+    'MG': '15/b',
+    'MR': '16/b',
+    'MINFO': '21/b',
+    'MAILB': '22/b',
+    'WKS': '23/b',
+    'NB': '24/b',
+    'NBSTAT': '25/b',
+    'NULL': '26/b',
+    'A6': '31/b',
+    'NXT': '32/b',
+    'X25': '41/b',
+    'ISDN': '42/b',
+    'RT': '43/b',
+    'NSAP': '44/b',
+    'NSAP-PTR': '45/b',
+    'PX': '46/b',
+    'EID': '11/a',
+    'NIMLOC': '12/a',
+    'ATMA': '13/a',
+    'SINK': '15/a',
+    'GPOS': '16/a',
+    'UINFO': '21/a',
+    'UID': '22/a',
+    'GID': '23/a',
+    'UNSPEC': '24/a',
+    'SPF': '25/a',
+    'NINFO': '26/a',
+    'RKEY': '31/a',
+    'TALINK': '32/a',
+    'NID': '33/qa',
+    'L32': '34/a',
+    'L64': '35/a',
+    'LP': '36/a',
+    'DOA': '41/a',
+}
+
+check_metrics["check_mk-unbound_type_stats"] = {}
+
+
+def clean_metric(answer: str) -> str:
+    return f'unbound_type_stats_{answer.replace(" ", "_").replace("-", "_")}'
+
+
+for answer_type, color in answer_types_most_common.items():
+    metric_info[clean_metric(answer_type)] = {
+        'title': _(f'Rate of {answer_type} type stats'),
+        'unit': '1/s',
+        'color': color,
+    }
+    check_metrics["check_mk-unbound_type_stats"].update({clean_metric(answer_type): {"auto_graph": False}})
+
+for answer_type, color in answer_types_common.items():
+    metric_info[clean_metric(answer_type)] = {
+        'title': _(f'Rate of {answer_type} type stats'),
+        'unit': '1/s',
+        'color': color,
+    }
+    check_metrics["check_mk-unbound_type_stats"].update({clean_metric(answer_type): {"auto_graph": False}})
+
+for answer_type, color in answer_types_obsolete.items():
+    metric_info[clean_metric(answer_type)] = {
+        'title': _(f'Rate of {answer_type} type stats'),
+        'unit': '1/s',
+        'color': color,
+    }
+    check_metrics["check_mk-unbound_type_stats"].update({clean_metric(answer_type): {"auto_graph": False}})
+
+graph_info['unbound_type_stats'] = {
+    'title': _('Rate of type stats'),
+    'metrics': [(
+        clean_metric(answer), METRIC_TYPE) for answer in sorted(list(answer_types_most_common.keys())[3:], reverse=True)
+    ],
+    'optional_metrics': [clean_metric(answer) for answer in answer_types_most_common]
+}
+
+graph_info['unbound_type_stats_common'] = {
+    'title': _('Rate of type stats (common)'),
+    'metrics': [(
+        clean_metric(answer), METRIC_TYPE) for answer in sorted(list(answer_types_common.keys()), reverse=True)
+    ],
+    'optional_metrics': [clean_metric(answer) for answer in answer_types_common]
+}
+
+graph_info['unbound_type_stats_obsolete'] = {
+    'title': _('Rate of type stats (obsolete)'),
+    'metrics': [(
+        clean_metric(answer), METRIC_TYPE) for answer in sorted(list(answer_types_obsolete.keys()), reverse=True)
+    ],
+    'optional_metrics': [clean_metric(answer) for answer in answer_types_obsolete]
+}
+
+if ADD_TOTAL:
+    graph_info['unbound_type_stats']['metrics'] = graph_info['unbound_type_stats']['metrics'] + [
+        (f'unbound_type_stats_Total_obsolete', METRIC_TYPE),
+        (f'unbound_type_stats_Total_common', METRIC_TYPE),
+        (f'unbound_type_stats_Total', 'line'),
+    ]
+    graph_info['unbound_type_stats_common']['metrics'] = graph_info['unbound_type_stats_common']['metrics'] + [
+        (f'unbound_type_stats_Total_common', 'line')]
+    graph_info['unbound_type_stats_obsolete']['metrics'] = graph_info['unbound_type_stats_obsolete']['metrics'] + [
+        (f'unbound_type_stats_Total_obsolete', 'line')]
+
+perfometer_info.append(
+    {
+        'type': 'logarithmic',
+        'metric': 'unbound_type_stats_Total',
+        'half_value': 100.0,
+        'exponent': 2,
+    }
+)
diff --git a/source/gui/metrics/unbound_unwanted_replies.py b/source/gui/metrics/unbound_unwanted_replies.py
new file mode 100644
index 0000000000000000000000000000000000000000..26ad2d463a5cb41458e0b91fe0e6eea6f049c39a
--- /dev/null
+++ b/source/gui/metrics/unbound_unwanted_replies.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+# -*- encoding: utf-8; py-indent-offset: 4 -*-
+
+# Copyright (C) 2022, Jan-Philipp Litza (PLUTEX) <jpl@plutex.de>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# modifications by thl-cmk[at]outlook[dot]com
+# 2024-02-21: changed import path form mk.gui.plugins.metrics to mk.gui.plugins.metrics.utils
+#             added metrics/graph for unbound_unwanted_replies
+#             moved to ~/local/lib/check_mk/gui/plugins/metrics (from local/share/check_mk/web/plugins/metrics)
+#             added perfometer for unbound_answers (NOERROR/SERVFAIL) and unbound_unwanted_replies
+
+from cmk.gui.i18n import _
+
+from cmk.gui.plugins.metrics.utils import (
+    metric_info,
+    graph_info,
+    perfometer_info,
+)
+
+metric_info['cache_hit_rate'] = {
+    'title': _('Cache hits per second'),
+    'unit': '1/s',
+    'color': '26/a',
+}
+
+graph_info['cache_hit_misses'] = {
+    'title': _('Cache Hits and Misses'),
+    'metrics': [
+        ('cache_hit_rate', 'line'),
+        ('cache_misses_rate', 'line'),
+    ],
+}
+
+metric_info['unbound_unwanted_replies'] = {
+    'title': _('Unwanted replies'),
+    'unit': '1/s',
+    'color': '26/a',
+}
+
+graph_info['unbound_unwanted_replies'] = {
+    'title': _('Unwanted replies'),
+    'metrics': [
+        ('unbound_unwanted_replies', 'area')
+    ],
+}
+
+perfometer_info.append({
+    'type': 'logarithmic',
+    'metric': 'unbound_unwanted_replies',
+    'half_value': 100.0,  # ome year
+    'exponent': 2,
+})
diff --git a/source/gui/wato/check_parameters/unbound.py b/source/gui/wato/check_parameters/unbound_answers.py
similarity index 67%
rename from source/gui/wato/check_parameters/unbound.py
rename to source/gui/wato/check_parameters/unbound_answers.py
index f20bb6e60c204a7c1ce94bccc3ff765e1436b5bd..457d8965db0e9de4bcc941cc20811f95c862b1ee 100644
--- a/source/gui/wato/check_parameters/unbound.py
+++ b/source/gui/wato/check_parameters/unbound_answers.py
@@ -44,38 +44,6 @@ from cmk.gui.valuespec import (
 )
 
 
-def _parameter_valuespec_unbound_cache():
-    return Dictionary(
-        title=_('Unbound: Cache'),
-        elements=[
-            ('cache_misses',
-             Tuple(
-                 title='Levels on cache misses per second',
-                 elements=[
-                     Float(title='warn', ),
-                     Float(title='crit', ),
-                 ])),
-            ('cache_hits',
-             Tuple(
-                 title='Lower levels for hits in %',
-                 elements=[
-                     Percentage(title='warn', ),
-                     Percentage(title='crit', ),
-                 ])),
-        ])
-
-
-rulespec_registry.register(
-    CheckParameterRulespecWithoutItem(
-        check_group_name='unbound_cache',
-        group=RulespecGroupCheckParametersApplications,
-        match_type='dict',
-        parameter_valuespec=_parameter_valuespec_unbound_cache,
-        title=lambda: _('Unbound Cache'),
-    )
-)
-
-
 def _parameter_valuespec_unbound_answers():
     return Dictionary(
         title=_('Unbound answers'),
@@ -91,6 +59,7 @@ def _parameter_valuespec_unbound_answers():
                              Float(title=_('Critical at'), unit=_('qps')),
                          ],
                          title=_('Upper levels in qps'),
+                         orientation='horizontal',
                      ),
                      Tuple(
                          elements=[
@@ -99,15 +68,16 @@ def _parameter_valuespec_unbound_answers():
                              FixedValue(value='%', totext=''),  # needed to decide between both variants
                          ],
                          title=_('Upper levels in %'),
+                         orientation='horizontal',
                      ),
                  ]))
             for answer in (
-                'NOERROR',
                 'FORMERR',
-                'SERVFAIL',
-                'NXDOMAIN',
+                'NOERROR',
                 'NOTIMPL',
+                'NXDOMAIN',
                 'REFUSED',
+                'SERVFAIL',
                 'nodata',
             )
         ],
@@ -123,28 +93,3 @@ rulespec_registry.register(
         title=lambda: _('Unbound Answers'),
     )
 )
-
-
-def _parameter_valuespec_unbound_replies():
-    return Dictionary(
-        title=_('Unbound: Replies'),
-        elements=[
-            ('unwanted_replies',
-             Tuple(
-                 title='Levels on unwanted replies per second',
-                 elements=[
-                     Float(title='warn', ),
-                     Float(title='crit', ),
-                 ])),
-        ])
-
-
-rulespec_registry.register(
-    CheckParameterRulespecWithoutItem(
-        check_group_name='unbound_replies',
-        group=RulespecGroupCheckParametersApplications,
-        match_type='dict',
-        parameter_valuespec=_parameter_valuespec_unbound_replies,
-        title=lambda: _('Unbound Replies'),
-    )
-)
diff --git a/source/gui/wato/check_parameters/unbound_bakery.py b/source/gui/wato/check_parameters/unbound_bakery.py
index d42570f1461550a8e41345ae48392e0cfbd453a3..24f04cb573b1d4d97f212617c81541d6a51b3845 100644
--- a/source/gui/wato/check_parameters/unbound_bakery.py
+++ b/source/gui/wato/check_parameters/unbound_bakery.py
@@ -8,13 +8,14 @@
 # Date  : unbound_bakery.py
 # File  : unbound_bakery.py
 
-# modifications by thl-cmk[at]outlook[dot]com
 # 2024-04-21: fixed missing FixedValue in import
-#             changed Alternative titles to "Upper levels in qps"/"Upper levels in %" to better differentiate between them
+#             changed Alternative titles to "Upper levels in qps"/"Upper levels in %"
+#             to better differentiate between them
 #             added explicit unit "%2
 #             added ruleset for bakery
 #             renamed to unbound.py (from unbound_parameters.py)
-#             moved to ~/local/lib/check_mk/gui/plugins/wato/check_parameters (from local/share/check_mk/web/plugins/wato)
+#             moved to ~/local/lib/check_mk/gui/plugins/wato/check_parameters
+#                   from local/share/check_mk/web/plugins/wato
 # 2024-05-14: separated WATO for bakery and check in two files
 # 2024-05-27: fixed crash in CRE version (has no cee elements)
 
diff --git a/source/gui/wato/check_parameters/unbound_cache.py b/source/gui/wato/check_parameters/unbound_cache.py
new file mode 100644
index 0000000000000000000000000000000000000000..51f6f5bb8a587520aca0a67d94e3ad43e52b1ebc
--- /dev/null
+++ b/source/gui/wato/check_parameters/unbound_cache.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2022, Jan-Philipp Litza (PLUTEX) <jpl@plutex.de>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# modifications by thl-cmk[at]outlook[dot]com
+# 2024-04-21: fixed missing FixedValue in import
+#             changed Alternative titles to "Upper levels in qps"/"Upper levels in %" to better differentiate between them
+#             added explicit unit "%2
+#             added ruleset for bakery
+#             renamed to unbound.py (from unbound_parameters.py)
+#             moved to ~/local/lib/check_mk/gui/plugins/wato/check_parameters (from local/share/check_mk/web/plugins/wato)
+# 2024-05-14: separated WATO for bakery and check in two files
+# 2024-05-22: added ruleset for unwanted replies
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.wato.utils import (
+    CheckParameterRulespecWithoutItem,
+    RulespecGroupCheckParametersApplications,
+    rulespec_registry,
+)
+
+from cmk.gui.valuespec import (
+    Dictionary,
+    Float,
+    Percentage,
+    Tuple,
+)
+
+
+def _parameter_valuespec_unbound_cache():
+    return Dictionary(
+        title=_('Unbound: Cache'),
+        elements=[
+            ('cache_misses',
+             Tuple(
+                 title='Levels on cache misses per second',
+                 elements=[
+                     Float(title='warn', ),
+                     Float(title='crit', ),
+                 ])),
+            ('cache_hits',
+             Tuple(
+                 title='Lower levels for hits in %',
+                 elements=[
+                     Percentage(title='warn', ),
+                     Percentage(title='crit', ),
+                 ])),
+        ])
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithoutItem(
+        check_group_name='unbound_cache',
+        group=RulespecGroupCheckParametersApplications,
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_unbound_cache,
+        title=lambda: _('Unbound Cache'),
+    )
+)
diff --git a/source/gui/wato/check_parameters/unbound_replies.py b/source/gui/wato/check_parameters/unbound_replies.py
new file mode 100644
index 0000000000000000000000000000000000000000..f4bad54ac218d53cb21296d23290847b52ea9ee6
--- /dev/null
+++ b/source/gui/wato/check_parameters/unbound_replies.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2022, Jan-Philipp Litza (PLUTEX) <jpl@plutex.de>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# modifications by thl-cmk[at]outlook[dot]com
+# 2024-04-21: fixed missing FixedValue in import
+#             changed Alternative titles to "Upper levels in qps"/"Upper levels in %" to better differentiate between them
+#             added explicit unit "%2
+#             added ruleset for bakery
+#             renamed to unbound.py (from unbound_parameters.py)
+#             moved to ~/local/lib/check_mk/gui/plugins/wato/check_parameters (from local/share/check_mk/web/plugins/wato)
+# 2024-05-14: separated WATO for bakery and check in two files
+# 2024-05-22: added ruleset for unwanted replies
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.wato.utils import (
+    CheckParameterRulespecWithoutItem,
+    RulespecGroupCheckParametersApplications,
+    rulespec_registry,
+)
+
+from cmk.gui.valuespec import (
+    Dictionary,
+    Float,
+    Tuple,
+)
+
+
+def _parameter_valuespec_unbound_replies():
+    return Dictionary(
+        title=_('Unbound: Replies'),
+        elements=[
+            ('unwanted_replies',
+             Tuple(
+                 title='Levels on unwanted replies per second',
+                 elements=[
+                     Float(title='warn', ),
+                     Float(title='crit', ),
+                 ])),
+        ])
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithoutItem(
+        check_group_name='unbound_replies',
+        group=RulespecGroupCheckParametersApplications,
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_unbound_replies,
+        title=lambda: _('Unbound Replies'),
+    )
+)
diff --git a/source/gui/wato/check_parameters/unbound_status.py b/source/gui/wato/check_parameters/unbound_status.py
new file mode 100644
index 0000000000000000000000000000000000000000..a58edde2d358d59536a853fae1d7ae6ba0184f46
--- /dev/null
+++ b/source/gui/wato/check_parameters/unbound_status.py
@@ -0,0 +1,41 @@
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2024-09-19
+# File  : unbound_status.py
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.wato.utils import (
+    CheckParameterRulespecWithoutItem,
+    RulespecGroupCheckParametersApplications,
+    rulespec_registry,
+)
+
+from cmk.gui.valuespec import (
+    Dictionary,
+    MonitoringState,
+)
+
+
+def _parameter_valuespec_unbound_status():
+    return Dictionary(
+        title=_('Unbound: status'),
+        elements=[
+            ('status_not_running',
+             MonitoringState(
+                 title='Monitoring state if unbound is not running',
+                 default_value=2,
+             )),
+        ])
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithoutItem(
+        check_group_name='unbound_status',
+        group=RulespecGroupCheckParametersApplications,
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_unbound_status,
+        title=lambda: _('Unbound status'),
+    )
+)
diff --git a/source/gui/wato/check_parameters/unbound_type_stats.py b/source/gui/wato/check_parameters/unbound_type_stats.py
new file mode 100644
index 0000000000000000000000000000000000000000..2e34f0f6c21b532d69efce97efd56aefeb87cd4a
--- /dev/null
+++ b/source/gui/wato/check_parameters/unbound_type_stats.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2024-08-02
+# File  : unbound_type_stats.py
+
+# based on the work of ruettimann[at]init7[dot]net
+
+
+from collections.abc import Sequence
+from typing import Final
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.wato.utils import (
+    CheckParameterRulespecWithoutItem,
+    RulespecGroupCheckParametersApplications,
+    rulespec_registry,
+)
+
+from cmk.gui.valuespec import (
+    Alternative,
+    Dictionary,
+    FixedValue,
+    Float,
+    Percentage,
+    Tuple,
+)
+
+# https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
+DNS_TYPES: Final[Sequence[str]] = [
+    'A',
+    'PTR',
+    'AAAA',
+    'ANY',
+    'CNAME',
+    'DNSKEY',
+    'DS',
+    'HINFO',
+    'HTTPS',
+    'MX',
+    'NAPTR',
+    'NS',
+    'RRSIG',
+    'SOA',
+    'SRV',
+    'SVCB',
+    'TXT',
+    # 'NULL',
+    # 'TYPE0',
+    # 'WKS',
+    'unknown',
+]
+
+DNS_TYPES_CHOICES: Final[Sequence[str]] = [(answer, answer) for answer in DNS_TYPES]
+
+_answer_levels = [
+    (f'levels_upper_{dns_type}',
+     Alternative(
+         title=f'Upper levels for {dns_type} answers',
+         show_alternative_title=True,
+         elements=[
+             Tuple(
+                 elements=[
+                     Float(title=_('Warning at'), unit=_('qps')),
+                     Float(title=_('Critical at'), unit=_('qps')),
+                 ],
+                 title=_('Upper levels in qps'),
+                 orientation='horizontal',
+             ),
+             Tuple(
+                 elements=[
+                     Percentage(title=_('Warning at'), unit=_('%')),
+                     Percentage(title=_('Critical at'), unit=_('%')),
+                     FixedValue(value='%', totext=''),  # needed to decide between both variants
+                 ],
+                 title=_('Upper levels in %'),
+                 orientation='horizontal',
+             ),
+         ]))
+    for dns_type in DNS_TYPES
+]
+
+_elements = _answer_levels
+# _elements.append(
+#     ('other_answer_types',
+#      DualListChoice(
+#          title=_('Other answer types'),
+#          help=_('Selected answer types will be summarized under "other"'),
+#          choices=DNS_TYPES_CHOICES,
+#          rows=len(DNS_TYPES_CHOICES),
+#          allow_empty=False,
+#      ))
+# )
+
+
+def _parameter_valuespec_unbound_type_stats():
+    return Dictionary(
+        title=_('Unbound type stats'),
+        elements=_elements,
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithoutItem(
+        check_group_name='unbound_type_stats',
+        group=RulespecGroupCheckParametersApplications,
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_unbound_type_stats,
+        title=lambda: _('Unbound Type Stats'),
+    )
+)
diff --git a/source/packages/unbound b/source/packages/unbound
index f04deacef6242002ca37ec8f84e17c871f0af313..646b36a772b9421d3e55a5849602f25a8cc669ef 100644
--- a/source/packages/unbound
+++ b/source/packages/unbound
@@ -11,17 +11,33 @@
                 'This plugin is based on the work of Jan-Philipp Litza '
                 '(PLUTEX) jpl[at]plutex[dor]de.\n'
                 'See:  https://exchange.checkmk.com/p/unbound for more '
-                'details.\n',
+                'details.\n'
+                '\n'
+                'ThX to ruettimann[at]init7[dot]net for the unbound_type_stats '
+                'check\n',
  'download_url': 'https://thl-cmk.hopto.org',
- 'files': {'agent_based': ['unbound.py', 'unbound_status.py'],
+ 'files': {'agent_based': ['unbound_status.py',
+                           'unbound.py',
+                           'unbound_answers.py',
+                           'unbound_cache.py',
+                           'unbound_unwanted_replies.py',
+                           'utils/unbound.py',
+                           'unbound_type_stats.py'],
            'agents': ['plugins/unbound'],
-           'gui': ['metrics/unbound.py',
-                   'wato/check_parameters/unbound.py',
-                   'wato/check_parameters/unbound_bakery.py'],
+           'gui': ['wato/check_parameters/unbound_bakery.py',
+                   'wato/check_parameters/unbound_answers.py',
+                   'wato/check_parameters/unbound_cache.py',
+                   'wato/check_parameters/unbound_replies.py',
+                   'metrics/unbound_answers.py',
+                   'metrics/unbound_cache.py',
+                   'metrics/unbound_unwanted_replies.py',
+                   'metrics/unbound_type_stats.py',
+                   'wato/check_parameters/unbound_type_stats.py',
+                   'wato/check_parameters/unbound_status.py'],
            'lib': ['python3/cmk/base/cee/plugins/bakery/unbound.py']},
  'name': 'unbound',
  'title': 'Unbound',
- 'version': '1.2.6-20240527',
+ 'version': '1.3.3-20240927',
  'version.min_required': '2.2.0b1',
  'version.packaged': 'cmk-mkp-tool 0.2.0',
  'version.usable_until': '2.4.0b1'}