Add DNS checker
Checks DNS server availability via ping then performs configurable DNS query (record_type: A, AAAA, TXT, MX, etc.). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
from .ping import PingChecker
|
from .ping import PingChecker
|
||||||
from .http import HttpChecker
|
from .http import HttpChecker
|
||||||
from .snmp import SnmpChecker
|
from .snmp import SnmpChecker
|
||||||
|
from .dns import DnsChecker
|
||||||
|
|
||||||
CHECKERS = {
|
CHECKERS = {
|
||||||
"ping": PingChecker,
|
"ping": PingChecker,
|
||||||
"http": HttpChecker,
|
"http": HttpChecker,
|
||||||
"snmp": SnmpChecker,
|
"snmp": SnmpChecker,
|
||||||
|
"dns": DnsChecker,
|
||||||
}
|
}
|
||||||
|
|||||||
68
checkers/dns.py
Normal file
68
checkers/dns.py
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
import dns.resolver
|
||||||
|
|
||||||
|
from .base import BaseChecker, CheckResult
|
||||||
|
from .ping import PingChecker
|
||||||
|
|
||||||
|
|
||||||
|
class DnsChecker(BaseChecker):
|
||||||
|
def check(self) -> CheckResult:
|
||||||
|
host = self.config["host"]
|
||||||
|
query_name = self.config["query"]
|
||||||
|
query_type = self.config.get("record_type", "A")
|
||||||
|
timeout = self.config.get("timeout", 5)
|
||||||
|
|
||||||
|
# First check if host is reachable via ping
|
||||||
|
ping_checker = PingChecker(self.name, {"host": host, "timeout": timeout})
|
||||||
|
ping_result = ping_checker.check()
|
||||||
|
|
||||||
|
if not ping_result.success:
|
||||||
|
return CheckResult(
|
||||||
|
success=False,
|
||||||
|
message=f"DNS server unreachable: {ping_result.message}",
|
||||||
|
response_time=None
|
||||||
|
)
|
||||||
|
|
||||||
|
# Now perform DNS query
|
||||||
|
resolver = dns.resolver.Resolver()
|
||||||
|
resolver.nameservers = [host]
|
||||||
|
resolver.timeout = timeout
|
||||||
|
resolver.lifetime = timeout
|
||||||
|
|
||||||
|
start = time.time()
|
||||||
|
try:
|
||||||
|
answers = resolver.resolve(query_name, query_type)
|
||||||
|
response_time = (time.time() - start) * 1000 # ms
|
||||||
|
|
||||||
|
records = [str(rdata) for rdata in answers]
|
||||||
|
return CheckResult(
|
||||||
|
success=True,
|
||||||
|
message=f"DNS {query_type} query OK ({len(records)} record(s))",
|
||||||
|
response_time=response_time,
|
||||||
|
details={"records": records, "query": query_name, "type": query_type}
|
||||||
|
)
|
||||||
|
except dns.resolver.NXDOMAIN:
|
||||||
|
return CheckResult(
|
||||||
|
success=False,
|
||||||
|
message=f"DNS query failed: {query_name} does not exist",
|
||||||
|
response_time=None
|
||||||
|
)
|
||||||
|
except dns.resolver.NoAnswer:
|
||||||
|
return CheckResult(
|
||||||
|
success=False,
|
||||||
|
message=f"DNS query failed: no {query_type} record for {query_name}",
|
||||||
|
response_time=None
|
||||||
|
)
|
||||||
|
except dns.resolver.Timeout:
|
||||||
|
return CheckResult(
|
||||||
|
success=False,
|
||||||
|
message="DNS query timeout",
|
||||||
|
response_time=None
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
return CheckResult(
|
||||||
|
success=False,
|
||||||
|
message=f"DNS error: {e}",
|
||||||
|
response_time=None
|
||||||
|
)
|
||||||
@@ -50,3 +50,13 @@ checks:
|
|||||||
community: "public"
|
community: "public"
|
||||||
oid: "1.3.6.1.2.1.1.1.0" # sysDescr
|
oid: "1.3.6.1.2.1.1.1.0" # sysDescr
|
||||||
interval: 120
|
interval: 120
|
||||||
|
|
||||||
|
# DNS checks
|
||||||
|
- id: pihole
|
||||||
|
name: "Pi-hole DNS"
|
||||||
|
type: dns
|
||||||
|
host: "192.168.1.10"
|
||||||
|
query: "google.com"
|
||||||
|
record_type: A # A, AAAA, TXT, MX, etc.
|
||||||
|
timeout: 5
|
||||||
|
interval: 60
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ paho-mqtt>=2.0.0
|
|||||||
PyYAML>=6.0
|
PyYAML>=6.0
|
||||||
pysnmp>=4.4.12
|
pysnmp>=4.4.12
|
||||||
requests>=2.31.0
|
requests>=2.31.0
|
||||||
|
dnspython>=2.4.0
|
||||||
|
|||||||
Reference in New Issue
Block a user