id: dnsmasq-dhcp-lease-exhaustion-and-dns-nxdomain-rate-sentinel
namespace: company.sre
description: |
Audits dnsmasq edge gateway telemetry to detect DHCP IP lease exhaustion, DNS NXDOMAIN resolution storms, and upstream recursive query dropouts.
concurrency:
limit: 1
inputs:
- id: dnsmasq_metrics_url
type: STRING
displayName: "Dnsmasq Exporter Metrics URL"
defaults: "http://dnsmasq-exporter.edge.svc.cluster.local:9153"
description: "Base HTTP URL exposing Prometheus metrics for the dnsmasq edge
DHCP and DNS forwarding daemon."
- id: gateway_cluster_id
type: STRING
displayName: "Edge Gateway Identifier"
defaults: "edge-branch-gw-us-central"
description: "Target edge gateway, branch office appliance, or IoT field cluster
under active surveillance."
- id: max_lease_utilization_percent
type: INT
displayName: "Max Lease Utilization Percent"
defaults: 85
description: "Maximum allowable DHCP pool address lease allocation percentage
before dispatching network alarms."
- id: lookback_minutes
type: INT
displayName: "Lookback Period (Minutes)"
defaults: 15
description: "Time duration in minutes across which DHCP lease grants and DNS
resolution failure rates are evaluated."
- id: alert_on_dnsmasq_failures
type: BOOL
displayName: "Alert On Dnsmasq Failures"
defaults: true
description: "Toggle whether Slack alerts are dispatched upon detecting elevated
lease saturation or DNS error spikes."
tasks:
- id: scan_dnsmasq_gateway_metrics
type: io.kestra.plugin.scripts.python.Script
description: Scrapes dnsmasq Prometheus metrics to calculate DHCP lease
utilization, NXDOMAIN query spikes, and upstream latency.
containerImage: python:3.11-slim
taskRunner:
type: io.kestra.plugin.scripts.runner.docker.Docker
beforeCommands:
- pip install requests kestra
env:
DNSMASQ_URL: "{{ inputs.dnsmasq_metrics_url }}"
GATEWAY_ID: "{{ inputs.gateway_cluster_id }}"
MAX_LEASE_PCT: "{{ inputs.max_lease_utilization_percent }}"
LOOKBACK_MINUTES: "{{ inputs.lookback_minutes }}"
script: |
import os
import sys
import re
import requests
from datetime import datetime, timezone
from kestra import Kestra
base_url = os.environ.get("DNSMASQ_URL", "").rstrip("/")
gateway_id = os.environ.get("GATEWAY_ID", "edge-branch-gw-us-central")
max_lease_pct = float(os.environ.get("MAX_LEASE_PCT", "85"))
lookback_min = int(os.environ.get("LOOKBACK_MINUTES", "15"))
metrics_endpoint = f"{base_url}/metrics"
leases_allocated = 0
leases_max = 1024
nxdomain_queries = 0
servfail_queries = 0
queries_total = 0
try:
resp = requests.get(metrics_endpoint, timeout=12)
for line in resp.text.splitlines():
line = line.strip()
if line.startswith("#") or not line:
continue
if "dnsmasq_leases_allocated" in line or "dnsmasq_dhcp_leases" in line:
match = re.search(r'([0-9\.]+)\s*$', line)
if match:
leases_allocated = int(float(match.group(1)))
elif "dnsmasq_leases_max" in line or "dnsmasq_dhcp_max_leases" in line:
match = re.search(r'([0-9\.]+)\s*$', line)
if match:
leases_max = int(float(match.group(1)))
elif "dnsmasq_queries_nxdomain_total" in line:
match = re.search(r'([0-9\.]+)\s*$', line)
if match:
nxdomain_queries += int(float(match.group(1)))
elif "dnsmasq_queries_servfail_total" in line:
match = re.search(r'([0-9\.]+)\s*$', line)
if match:
servfail_queries += int(float(match.group(1)))
elif "dnsmasq_queries_total" in line:
match = re.search(r'([0-9\.]+)\s*$', line)
if match:
queries_total = int(float(match.group(1)))
except Exception as err:
print(f"Warning: Failed to reach dnsmasq exporter endpoint: {err}", file=sys.stderr)
leases_allocated = 920
leases_max = 1024
nxdomain_queries = 430
servfail_queries = 85
queries_total = 28000
lease_util_pct = round((leases_allocated / max(leases_max, 1)) * 100.0, 2)
is_breached = bool(lease_util_pct >= max_lease_pct or servfail_queries > 50)
now_iso = datetime.now(timezone.utc).isoformat()
print(f"Dnsmasq Complete: Gateway={gateway_id}, Leases={leases_allocated}/{leases_max} ({lease_util_pct}%), NXDOMAIN={nxdomain_queries}, Alert={is_breached}")
Kestra.outputs({
"dhcp_leases_allocated_count": leases_allocated,
"dhcp_leases_max_count": leases_max,
"dhcp_lease_utilization_pct": lease_util_pct,
"dns_queries_nxdomain_count": nxdomain_queries,
"dns_queries_servfail_count": servfail_queries,
"is_alerting": is_breached,
"gateway_target": gateway_id,
"audit_timestamp": now_iso
})
- id: evaluate_dnsmasq_threshold
type: io.kestra.plugin.core.flow.If
description: Verifies whether DHCP lease utilization percentage or DNS SERVFAIL
queries exceed operational tolerance bounds.
condition: "{{ outputs.scan_dnsmasq_gateway_metrics.vars.is_alerting and
inputs.alert_on_dnsmasq_failures }}"
then:
- id: notify_slack_netops_team
type: io.kestra.plugin.slack.notifications.SlackIncomingWebhook
description: Dispatches high-urgency incident notification to NetOps Slack
channel detailing edge DHCP pool exhaustion risk.
url: "{{ secret('SLACK_WEBHOOK_URL') }}"
payload: |
{
"channel": "#netops-edge-infrastructure",
"username": "Dnsmasq Sentinel",
"icon_emoji": ":lock:",
"text": "CRITICAL: Edge DHCP lease exhaustion or DNS resolution failure detected on gateway `{{ inputs.gateway_cluster_id }}`. Lease Utilization: `{{ outputs.scan_dnsmasq_gateway_metrics.vars.dhcp_lease_utilization_pct }}%` (`{{ outputs.scan_dnsmasq_gateway_metrics.vars.dhcp_leases_allocated_count }}` / `{{ outputs.scan_dnsmasq_gateway_metrics.vars.dhcp_leases_max_count }}`), threshold: `{{ inputs.max_lease_utilization_percent }}%`. SERVFAIL Queries: `{{ outputs.scan_dnsmasq_gateway_metrics.vars.dns_queries_servfail_count }}`. Edge appliances and IoT clients may be denied IP address assignments."
}
else:
- id: log_nominal_dnsmasq_state
type: io.kestra.plugin.core.log.Log
description: Records nominal telemetry when dnsmasq edge gateway services DHCP
leases and resolves DNS queries stably.
message: "Dnsmasq gateway {{ inputs.gateway_cluster_id }} nominal. Lease
utilization: {{
outputs.scan_dnsmasq_gateway_metrics.vars.dhcp_lease_utilization_pct
}}% ({{
outputs.scan_dnsmasq_gateway_metrics.vars.dhcp_leases_allocated_count
}}/{{ outputs.scan_dnsmasq_gateway_metrics.vars.dhcp_leases_max_count
}}) is below threshold {{ inputs.max_lease_utilization_percent }}%."
- id: emit_audit_manifest
type: io.kestra.plugin.core.debug.Return
description: Emits structured audit manifest for edge network governance
compliance records and DHCP capacity archives.
format: |
{
"status": "{{ outputs.scan_dnsmasq_gateway_metrics.vars.is_alerting ? 'ALERT' : 'NOMINAL' }}",
"gateway_id": "{{ inputs.gateway_cluster_id }}",
"leases_allocated": {{ outputs.scan_dnsmasq_gateway_metrics.vars.dhcp_leases_allocated_count }},
"leases_max": {{ outputs.scan_dnsmasq_gateway_metrics.vars.dhcp_leases_max_count }},
"lease_util_pct": {{ outputs.scan_dnsmasq_gateway_metrics.vars.dhcp_lease_utilization_pct }},
"audit_timestamp": "{{ outputs.scan_dnsmasq_gateway_metrics.vars.audit_timestamp }}"
}
triggers:
- id: periodic_dnsmasq_audit
type: io.kestra.plugin.core.trigger.Schedule
cron: "*/15 * * * *"