diff --git a/data/templates/prometheus/blackbox_exporter.service.j2 b/data/templates/prometheus/blackbox_exporter.service.j2
new file mode 100644
index 000000000..e93030246
--- /dev/null
+++ b/data/templates/prometheus/blackbox_exporter.service.j2
@@ -0,0 +1,21 @@
+{% set vrf_command = 'ip vrf exec ' ~ vrf ~ ' runuser -u node_exporter -- ' if vrf is vyos_defined else '' %}
+[Unit]
+Description=Blackbox Exporter
+Documentation=https://github.com/prometheus/blackbox_exporter
+After=network.target
+
+[Service]
+{% if vrf is not vyos_defined %}
+User=node_exporter
+{% endif %}
+ExecStart={{ vrf_command }}/usr/sbin/blackbox_exporter \
+{% if listen_address is vyos_defined %}
+{%     for address in listen_address %}
+        --web.listen-address={{ address }}:{{ port }} \
+{%     endfor %}
+{% else %}
+        --web.listen-address=:{{ port }} \
+{% endif %}
+        --config.file=/run/blackbox_exporter/config.yml
+[Install]
+WantedBy=multi-user.target
diff --git a/data/templates/prometheus/blackbox_exporter.yml.j2 b/data/templates/prometheus/blackbox_exporter.yml.j2
new file mode 100644
index 000000000..ba2eecd77
--- /dev/null
+++ b/data/templates/prometheus/blackbox_exporter.yml.j2
@@ -0,0 +1,23 @@
+modules:
+{% if modules is defined and modules.dns is defined and modules.dns.name is defined %}
+{%     for module_name, module_config in modules.dns.name.items() %}
+  {{ module_name }}:
+    prober: dns
+    timeout: {{ module_config.timeout }}s
+    dns:
+      query_name: "{{ module_config.query_name }}"
+      query_type: "{{ module_config.query_type }}"
+      preferred_ip_protocol: "{{ module_config.preferred_ip_protocol | replace('v', '') }}"
+      ip_protocol_fallback: {{ 'true' if module_config.ip_protocol_fallback is vyos_defined else 'false' }}
+{%     endfor %}
+{% endif %}
+{% if modules is defined and modules.icmp is vyos_defined and modules.icmp.name is vyos_defined %}
+{%     for module_name, module_config in modules.icmp.name.items() %}
+  {{ module_name }}:
+    prober: icmp
+    timeout: {{ module_config.timeout }}s
+    icmp:
+      preferred_ip_protocol: "{{ module_config.preferred_ip_protocol | replace('v', '') }}"
+      ip_protocol_fallback: {{ 'true' if module_config.ip_protocol_fallback is vyos_defined else 'false' }}
+{%     endfor %}
+{% endif %}
\ No newline at end of file
diff --git a/debian/control b/debian/control
index 08b86356a..b1cb5c4ef 100644
--- a/debian/control
+++ b/debian/control
@@ -1,390 +1,393 @@
 Source: vyos-1x
 Section: contrib/net
 Priority: extra
 Maintainer: VyOS Package Maintainers <maintainers@vyos.net>
 Build-Depends:
   debhelper (>= 9),
   dh-python,
   fakeroot,
   gcc,
   iproute2,
   libvyosconfig0 (>= 0.0.7),
   libzmq3-dev,
   python3 (>= 3.10),
 # For QA
   pylint,
 # For generating command definitions
   python3-lxml,
   python3-xmltodict,
 # For running tests
   python3-coverage,
   python3-hurry.filesize,
   python3-netaddr,
   python3-netifaces,
   python3-nose,
   python3-jinja2,
   python3-paramiko,
   python3-passlib,
   python3-psutil,
   python3-requests,
   python3-setuptools,
   python3-tabulate,
   python3-zmq,
   quilt,
   whois
 Standards-Version: 3.9.6
 
 Package: vyos-1x
 Architecture: amd64 arm64
 Pre-Depends:
   libpam-runtime [amd64],
   libnss-tacplus [amd64],
   libpam-tacplus [amd64],
   libpam-radius-auth [amd64]
 Depends:
 ## Fundamentals
   ${python3:Depends} (>= 3.10),
   dialog,
   libvyosconfig0,
   libpam-cap,
   bash-completion,
   ipvsadm,
   udev,
   less,
   at,
   rsync,
   vyatta-bash,
   vyatta-biosdevname,
   vyatta-cfg,
   vyos-http-api-tools,
   vyos-utils,
 ## End of Fundamentals
 ## Python libraries used in multiple modules and scripts
   python3,
   python3-cryptography,
   python3-hurry.filesize,
   python3-inotify,
   python3-jinja2,
   python3-jmespath,
   python3-netaddr,
   python3-netifaces,
   python3-paramiko,
   python3-passlib,
   python3-pyroute2,
   python3-psutil,
   python3-pyhumps,
   python3-pystache,
   python3-pyudev,
   python3-six,
   python3-tabulate,
   python3-voluptuous,
   python3-xmltodict,
   python3-zmq,
 ## End of Python libraries
 ## Basic System services and utilities
   coreutils,
   sudo,
   systemd,
   bsdmainutils,
   openssl,
   curl,
   dbus,
   file,
   iproute2 (>= 6.0.0),
   linux-cpupower,
 # ipaddrcheck is widely used in IP value validators
   ipaddrcheck,
   ethtool (>= 6.10),
   lm-sensors,
   procps,
   netplug,
   sed,
   ssl-cert,
   tuned,
   beep,
   wide-dhcpv6-client,
 # Generic colorizer
   grc,
 ## End of System services and utilities
 ## For the installer
   fdisk,
   gdisk,
   mdadm,
   efibootmgr,
   libefivar1,
   dosfstools,
   grub-efi-amd64-signed [amd64],
   grub-efi-arm64-bin [arm64],
   mokutil [amd64],
   shim-signed [amd64],
   sbsigntool [amd64],
 # Image signature verification tool
   minisign,
 # Live filesystem tools
   squashfs-tools,
   fuse-overlayfs,
 ## End installer
   auditd,
   iputils-arping,
   iputils-ping,
   isc-dhcp-client,
 # For "vpn pptp", "vpn l2tp", "vpn sstp", "service ipoe-server"
   accel-ppp,
 # End "vpn pptp", "vpn l2tp", "vpn sstp", "service ipoe-server"
   avahi-daemon,
   conntrack,
   conntrackd,
 ## Conf mode features
 # For "interfaces wireless"
   hostapd,
   hsflowd,
   iw,
   wireless-regdb,
   wpasupplicant (>= 0.6.7),
 # End "interfaces wireless"
 # For "interfaces wwan"
   modemmanager,
   usb-modeswitch,
   libqmi-utils,
 # End "interfaces wwan"
 # For "interfaces openvpn"
   openvpn,
   openvpn-auth-ldap,
   openvpn-auth-radius,
   openvpn-otp,
   openvpn-dco,
   libpam-google-authenticator,
 # End "interfaces openvpn"
 # For "interfaces wireguard"
   wireguard-tools,
   qrencode,
 # End "interfaces wireguard"
 # For "interfaces pppoe"
   pppoe,
 # End "interfaces pppoe"
 # For "interfaces sstpc"
   sstp-client,
 # End "interfaces sstpc"
 # For "protocols *"
   frr (>= 10.2),
   frr-pythontools,
   frr-rpki-rtrlib,
   frr-snmp,
 # End "protocols *"
 # For "protocols nhrp" (part of DMVPN)
   opennhrp,
 # End "protocols nhrp"
 # For "protocols igmp-proxy"
   igmpproxy,
 # End "protocols igmp-proxy"
 # For "pki"
   certbot,
 # End "pki"
 # For "service console-server"
   conserver-client,
   conserver-server,
   console-data,
   dropbear,
 # End "service console-server"
 # For "service aws glb"
   aws-gwlbtun,
 # For "service dns dynamic"
   ddclient (>= 3.11.1),
 # End "service dns dynamic"
 # # For "service ids"
   fastnetmon [amd64],
   suricata,
   suricata-update,
 # End "service ids"
 # # For "service ndp-proxy"
   ndppd,
 # End "service ndp-proxy"
 # For "service router-advert"
   radvd,
 # End "service route-advert"
 # For "load-balancing haproxy"
   haproxy,
 # End "load-balancing haproxy"
 # For "load-balancing wan"
   vyatta-wanloadbalance,
 # End "load-balancing wan"
 # For "service dhcp-relay"
   isc-dhcp-relay,
 # For "service dhcp-server"
   kea,
 # End "service dhcp-server"
 # For "service lldp"
   lldpd,
 # End "service lldp"
 # For "service https"
   nginx-light,
 # End "service https"
 # For "service ssh"
   openssh-server,
   sshguard,
 # End "service ssh"
 # For "service salt-minion"
   salt-minion,
 # End "service salt-minion"
 # For "service snmp"
   snmp,
   snmpd,
 # End "service snmp"
 # For "service webproxy"
   squid,
   squidclient,
   squidguard,
 # End "service webproxy"
 # For "service monitoring prometheus node-exporter"
   node-exporter,
 # End "service monitoring prometheus node-exporter"
 # For "service monitoring prometheus frr-exporter"
   frr-exporter,
 # End "service monitoring prometheus frr-exporter"
+# For "service monitoring prometheus blackbox-exporter"
+  blackbox-exporter,
+# End "service monitoring prometheus blackbox-exporter"
 # For "service monitoring telegraf"
   telegraf (>= 1.20),
 # End "service monitoring telegraf"
 # For "service monitoring zabbix-agent"
   zabbix-agent2,
 # End "service monitoring zabbix-agent"
 # For "service tftp-server"
   tftpd-hpa,
 # End "service tftp-server"
 # For "service dns forwarding"
   pdns-recursor,
 # End "service dns forwarding"
 # For "service sla owamp"
   owamp-client,
   owamp-server,
 # End "service sla owamp"
 # For "service sla twamp"
   twamp-client,
   twamp-server,
 # End "service sla twamp"
 # For "service broadcast-relay"
   udp-broadcast-relay,
 # End "service broadcast-relay"
 # For "high-availability vrrp"
   keepalived (>=2.0.5),
 # End "high-availability-vrrp"
 # For "system console"
   util-linux,
 # End "system console"
 # For "system task-scheduler"
   cron,
 # End "system task-scheduler"
 # For "system lcd"
   lcdproc,
   lcdproc-extra-drivers,
 # End "system lcd"
 # For "system config-management commit-archive"
   git,
 # End "system config-management commit-archive"
 # For firewall
   libndp-tools,
   libnetfilter-conntrack3,
   libnfnetlink0,
   nfct,
   nftables (>= 0.9.3),
 # For "vpn ipsec"
   strongswan (>= 5.9),
   strongswan-swanctl (>= 5.9),
   charon-systemd,
   libcharon-extra-plugins (>=5.9),
   libcharon-extauth-plugins (>=5.9),
   libstrongswan-extra-plugins (>=5.9),
   libstrongswan-standard-plugins (>=5.9),
   python3-vici (>= 5.7.2),
 # End "vpn ipsec"
 # For "nat64"
   jool,
 # End "nat64"
 # For "system conntrack modules rtsp"
   nat-rtsp,
 # End "system conntrack modules rtsp"
 # For "service ntp"
   chrony,
 # End "system ntp"
 # For "vpn openconnect"
   ocserv,
 # End "vpn openconnect"
 # For "system flow-accounting"
   pmacct (>= 1.6.0),
 # End "system flow-accounting"
 # For "system syslog"
   rsyslog,
 # End "system syslog"
 # For "system option keyboard-layout"
   kbd,
 # End "system option keyboard-layout"
 # For "container"
   podman (>=4.9.5),
   netavark,
   aardvark-dns,
 # iptables is only used for containers now, not the the firewall CLI
   iptables,
 # End container
 ## End Configuration mode
 ## Operational mode
 # Used for hypervisor model in "run show version"
   hvinfo,
 # For "run traceroute"
   traceroute,
 # For "run monitor traffic"
   tcpdump,
 # End "run monitor traffic"
 # For "show hardware dmi"
   dmidecode,
 # For "run show hardware storage smart"
   smartmontools,
 # For "run show hardware scsi"
   lsscsi,
 # For "run show hardware pci"
   pciutils,
 # For "show hardware usb"
   usbutils,
 # For "run show hardware storage nvme"
   nvme-cli,
 # For "run monitor bandwidth-test"
   iperf,
   iperf3,
 # End "run monitor bandwidth-test"
 # For "run wake-on-lan"
   etherwake,
 # For "run force ipv6-nd"
   ndisc6,
 # For "run monitor bandwidth"
   bmon,
 # For "run format disk"
   parted,
 # End Operational mode
 ## TPM tools
   cryptsetup,
   tpm2-tools,
 ## End TPM tools
 ## Optional utilities
   easy-rsa,
   tcptraceroute,
   mtr-tiny,
   telnet,
   stunnel4,
   uidmap
 ## End optional utilities
 Description: VyOS configuration scripts and data
  VyOS configuration scripts, interface definitions, and everything
 
 Package: vyos-1x-vmware
 Architecture: amd64
 Depends:
  vyos-1x,
  open-vm-tools
 Description: VyOS configuration scripts and data for VMware
  Adds configuration files required for VyOS running on VMware hosts.
 
 Package: vyos-1x-smoketest
 Architecture: all
 Depends:
  skopeo,
  snmp,
  vyos-1x
 Description: VyOS build sanity checking toolkit
diff --git a/interface-definitions/include/monitoring/blackbox-exporter-module-commons.xml.i b/interface-definitions/include/monitoring/blackbox-exporter-module-commons.xml.i
new file mode 100644
index 000000000..a97eb5232
--- /dev/null
+++ b/interface-definitions/include/monitoring/blackbox-exporter-module-commons.xml.i
@@ -0,0 +1,39 @@
+<!-- include start from monitoring/blackbox-module-commons.xml.i -->
+<leafNode name="timeout">
+  <properties>
+    <help>Timeout in seconds for the probe request</help>
+    <valueHelp>
+      <format>u32:1-60</format>
+      <description>Timeout in seconds</description>
+    </valueHelp>
+    <constraint>
+      <validator name="numeric" argument="--range 1-60"/>
+    </constraint>
+    <constraintErrorMessage>Timeout must be between 1 and 60 seconds</constraintErrorMessage>
+  </properties>
+  <defaultValue>5</defaultValue>
+</leafNode>
+<leafNode name="preferred-ip-protocol">
+  <properties>
+    <help>Preferred IP protocol for this module</help>
+    <valueHelp>
+      <format>ipv4</format>
+      <description>Prefer IPv4</description>
+    </valueHelp>
+    <valueHelp>
+      <format>ipv6</format>
+      <description>Prefer IPv6</description>
+    </valueHelp>
+    <constraint>
+      <regex>(ipv4|ipv6)</regex>
+    </constraint>
+  </properties>
+  <defaultValue>ip6</defaultValue>
+</leafNode>
+<leafNode name="ip-protocol-fallback">
+  <properties>
+    <help>Allow fallback to other IP protocol if necessary</help>
+    <valueless/>
+  </properties>
+</leafNode>
+<!-- include end -->
\ No newline at end of file
diff --git a/interface-definitions/service_monitoring_prometheus.xml.in b/interface-definitions/service_monitoring_prometheus.xml.in
index 24f31e15c..740900f1f 100644
--- a/interface-definitions/service_monitoring_prometheus.xml.in
+++ b/interface-definitions/service_monitoring_prometheus.xml.in
@@ -1,45 +1,121 @@
 <?xml version="1.0"?>
 <interfaceDefinition>
   <node name="service">
     <children>
       <node name="monitoring">
         <children>
           <node name="prometheus" owner="${vyos_conf_scripts_dir}/service_monitoring_prometheus.py">
             <properties>
               <help>Prometheus metric exporter</help>
               <priority>1280</priority>
             </properties>
             <children>
               <node name="node-exporter">
                 <properties>
                   <help>Prometheus exporter for hardware and operating system metrics</help>
                 </properties>
                 <children>
                   #include <include/listen-address.xml.i>
                   #include <include/port-number.xml.i>
                   <leafNode name="port">
                     <defaultValue>9100</defaultValue>
                   </leafNode>
                   #include <include/interface/vrf.xml.i>
                 </children>
               </node>
               <node name="frr-exporter">
                 <properties>
                   <help>Prometheus exporter for FRR metrics</help>
                 </properties>
                 <children>
                   #include <include/listen-address.xml.i>
                   #include <include/port-number.xml.i>
                   <leafNode name="port">
                     <defaultValue>9342</defaultValue>
                   </leafNode>
                   #include <include/interface/vrf.xml.i>
                 </children>
               </node>
+              <node name="blackbox-exporter">
+                <properties>
+                  <help>Prometheus exporter for probing endpoints</help>
+                </properties>
+                <children>
+                  #include <include/listen-address.xml.i>
+                  #include <include/port-number.xml.i>
+                  <leafNode name="port">
+                    <defaultValue>9115</defaultValue>
+                  </leafNode>
+                  #include <include/interface/vrf.xml.i>
+                  <node name="modules">
+                    <properties>
+                      <help>Configure blackbox exporter modules</help>
+                    </properties>
+                    <children>
+                      <node name="dns">
+                        <properties>
+                          <help>Configure dns module</help>
+                        </properties>
+                        <children>
+                          <tagNode name="name">
+                            <properties>
+                              <help>Name of the dns module</help>
+                            </properties>
+                            <children>
+                              <leafNode name="query-name">
+                                <properties>
+                                  <help>Name to be queried</help>
+                                  <constraint>
+                                    <validator name="fqdn"/>
+                                  </constraint>
+                                </properties>
+                              </leafNode>
+                              <leafNode name="query-type">
+                                <properties>
+                                  <help>DNS query type</help>
+                                  <valueHelp>
+                                    <format>ANY</format>
+                                    <description>Query any DNS record</description>
+                                  </valueHelp>
+                                  <valueHelp>
+                                    <format>A</format>
+                                    <description>Query IPv4 address record</description>
+                                  </valueHelp>
+                                  <valueHelp>
+                                    <format>AAAA</format>
+                                    <description>Query IPv6 address record</description>
+                                  </valueHelp>
+                                </properties>
+                                <defaultValue>ANY</defaultValue>
+                              </leafNode>
+                              #include <include/monitoring/blackbox-exporter-module-commons.xml.i>
+                            </children>
+                          </tagNode>
+                        </children>
+                      </node>
+                      <node name="icmp">
+                        <properties>
+                          <help>Configure icmp module</help>
+                        </properties>
+                        <children>
+                          <tagNode name="name">
+                            <properties>
+                              <help>Name of the icmp module</help>
+                            </properties>
+                            <children>
+                              #include <include/monitoring/blackbox-exporter-module-commons.xml.i>
+                            </children>
+                          </tagNode>
+                        </children>
+                      </node>
+                    </children>
+                  </node>
+                </children>
+              </node>
             </children>
           </node>
         </children>
       </node>
     </children>
   </node>
 </interfaceDefinition>
diff --git a/smoketest/scripts/cli/test_service_monitoring_prometheus.py b/smoketest/scripts/cli/test_service_monitoring_prometheus.py
index dae103e4b..df737f840 100755
--- a/smoketest/scripts/cli/test_service_monitoring_prometheus.py
+++ b/smoketest/scripts/cli/test_service_monitoring_prometheus.py
@@ -1,80 +1,154 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2024 VyOS maintainers and contributors
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License version 2 or later as
 # published by the Free Software Foundation.
 #
 # 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, see <http://www.gnu.org/licenses/>.
 
 import unittest
 
 from base_vyostest_shim import VyOSUnitTestSHIM
 from vyos.utils.process import process_named_running
 from vyos.utils.file import read_file
 
 NODE_EXPORTER_PROCESS_NAME = 'node_exporter'
 FRR_EXPORTER_PROCESS_NAME = 'frr_exporter'
+BLACKBOX_EXPORTER_PROCESS_NAME = 'blackbox_exporter'
 
 base_path = ['service', 'monitoring', 'prometheus']
 listen_if = 'dum3421'
 listen_ip = '192.0.2.1'
 node_exporter_service_file = '/etc/systemd/system/node_exporter.service'
 frr_exporter_service_file = '/etc/systemd/system/frr_exporter.service'
+blackbox_exporter_service_file = '/etc/systemd/system/blackbox_exporter.service'
 
 
 class TestMonitoringPrometheus(VyOSUnitTestSHIM.TestCase):
     @classmethod
     def setUpClass(cls):
         # call base-classes classmethod
         super(TestMonitoringPrometheus, cls).setUpClass()
         # create a test interfaces
         cls.cli_set(
             cls, ['interfaces', 'dummy', listen_if, 'address', listen_ip + '/32']
         )
 
     @classmethod
     def tearDownClass(cls):
         cls.cli_delete(cls, ['interfaces', 'dummy', listen_if])
         super(TestMonitoringPrometheus, cls).tearDownClass()
 
     def tearDown(self):
         self.cli_delete(base_path)
         self.cli_commit()
         self.assertFalse(process_named_running(NODE_EXPORTER_PROCESS_NAME))
         self.assertFalse(process_named_running(FRR_EXPORTER_PROCESS_NAME))
 
     def test_01_node_exporter(self):
         self.cli_set(base_path + ['node-exporter', 'listen-address', listen_ip])
 
         # commit changes
         self.cli_commit()
 
         file_content = read_file(node_exporter_service_file)
         self.assertIn(f'{listen_ip}:9100', file_content)
 
         # Check for running process
         self.assertTrue(process_named_running(NODE_EXPORTER_PROCESS_NAME))
 
     def test_02_frr_exporter(self):
         self.cli_set(base_path + ['frr-exporter', 'listen-address', listen_ip])
 
         # commit changes
         self.cli_commit()
 
         file_content = read_file(frr_exporter_service_file)
         self.assertIn(f'{listen_ip}:9342', file_content)
 
         # Check for running process
         self.assertTrue(process_named_running(FRR_EXPORTER_PROCESS_NAME))
 
+    def test_03_blackbox_exporter(self):
+        self.cli_set(base_path + ['blackbox-exporter', 'listen-address', listen_ip])
+
+        # commit changes
+        self.cli_commit()
+
+        file_content = read_file(blackbox_exporter_service_file)
+        self.assertIn(f'{listen_ip}:9115', file_content)
+
+        # Check for running process
+        self.assertTrue(process_named_running(BLACKBOX_EXPORTER_PROCESS_NAME))
+
+    def test_04_blackbox_exporter_with_config(self):
+        self.cli_set(base_path + ['blackbox-exporter', 'listen-address', listen_ip])
+        self.cli_set(
+            base_path
+            + [
+                'blackbox-exporter',
+                'modules',
+                'dns',
+                'name',
+                'dns_ip4',
+                'preferred-ip-protocol',
+                'ipv4',
+            ]
+        )
+        self.cli_set(
+            base_path
+            + [
+                'blackbox-exporter',
+                'modules',
+                'dns',
+                'name',
+                'dns_ip4',
+                'query-name',
+                'vyos.io',
+            ]
+        )
+        self.cli_set(
+            base_path
+            + [
+                'blackbox-exporter',
+                'modules',
+                'dns',
+                'name',
+                'dns_ip4',
+                'query-type',
+                'A',
+            ]
+        )
+        self.cli_set(
+            base_path
+            + [
+                'blackbox-exporter',
+                'modules',
+                'icmp',
+                'name',
+                'icmp_ip6',
+                'preferred-ip-protocol',
+                'ipv6',
+            ]
+        )
+
+        # commit changes
+        self.cli_commit()
+
+        file_content = read_file(blackbox_exporter_service_file)
+        self.assertIn(f'{listen_ip}:9115', file_content)
+
+        # Check for running process
+        self.assertTrue(process_named_running(BLACKBOX_EXPORTER_PROCESS_NAME))
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=2)
diff --git a/src/conf_mode/service_monitoring_prometheus.py b/src/conf_mode/service_monitoring_prometheus.py
index e0a9fc4ef..42628b05c 100755
--- a/src/conf_mode/service_monitoring_prometheus.py
+++ b/src/conf_mode/service_monitoring_prometheus.py
@@ -1,145 +1,199 @@
 #!/usr/bin/env python3
 #
 # Copyright (C) 2024 VyOS maintainers and contributors
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License version 2 or later as
 # published by the Free Software Foundation.
 #
 # 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, see <http://www.gnu.org/licenses/>.
 
 import os
 
 from sys import exit
 
 from vyos.config import Config
 from vyos.configdict import is_node_changed
 from vyos.configverify import verify_vrf
 from vyos.template import render
 from vyos.utils.process import call
 from vyos import ConfigError
 from vyos import airbag
 
 
 airbag.enable()
 
 node_exporter_service_file = '/etc/systemd/system/node_exporter.service'
 node_exporter_systemd_service = 'node_exporter.service'
 
 frr_exporter_service_file = '/etc/systemd/system/frr_exporter.service'
 frr_exporter_systemd_service = 'frr_exporter.service'
 
+blackbox_exporter_service_file = '/etc/systemd/system/blackbox_exporter.service'
+blackbox_exporter_systemd_service = 'blackbox_exporter.service'
+
 
 def get_config(config=None):
     if config:
         conf = config
     else:
         conf = Config()
     base = ['service', 'monitoring', 'prometheus']
     if not conf.exists(base):
         return None
 
     monitoring = conf.get_config_dict(
         base, key_mangling=('-', '_'), get_first_key=True, with_recursive_defaults=True
     )
 
     tmp = is_node_changed(conf, base + ['node-exporter', 'vrf'])
     if tmp:
         monitoring.update({'node_exporter_restart_required': {}})
 
     tmp = is_node_changed(conf, base + ['frr-exporter', 'vrf'])
     if tmp:
         monitoring.update({'frr_exporter_restart_required': {}})
 
+    tmp = False
+    for node in ['vrf', 'config-file']:
+        tmp = tmp or is_node_changed(conf, base + ['blackbox-exporter', node])
+    if tmp:
+        monitoring.update({'blackbox_exporter_restart_required': {}})
+
     return monitoring
 
 
 def verify(monitoring):
     if not monitoring:
         return None
 
     if 'node_exporter' in monitoring:
         verify_vrf(monitoring['node_exporter'])
 
     if 'frr_exporter' in monitoring:
         verify_vrf(monitoring['frr_exporter'])
 
+    if 'blackbox_exporter' in monitoring:
+        verify_vrf(monitoring['blackbox_exporter'])
+
+        if (
+            'modules' in monitoring['blackbox_exporter']
+            and 'dns' in monitoring['blackbox_exporter']['modules']
+            and 'name' in monitoring['blackbox_exporter']['modules']['dns']
+        ):
+            for mod_name, mod_config in monitoring['blackbox_exporter']['modules'][
+                'dns'
+            ]['name'].items():
+                if 'query_name' not in mod_config:
+                    raise ConfigError(
+                        f'query name not specified in dns module {mod_name}'
+                    )
+
     return None
 
 
 def generate(monitoring):
     if not monitoring or 'node_exporter' not in monitoring:
         # Delete systemd files
         if os.path.isfile(node_exporter_service_file):
             os.unlink(node_exporter_service_file)
 
     if not monitoring or 'frr_exporter' not in monitoring:
         # Delete systemd files
         if os.path.isfile(frr_exporter_service_file):
             os.unlink(frr_exporter_service_file)
 
+    if not monitoring or 'blackbox_exporter' not in monitoring:
+        # Delete systemd files
+        if os.path.isfile(blackbox_exporter_service_file):
+            os.unlink(blackbox_exporter_service_file)
+
     if not monitoring:
         return None
 
     if 'node_exporter' in monitoring:
         # Render node_exporter node_exporter_service_file
         render(
             node_exporter_service_file,
             'prometheus/node_exporter.service.j2',
             monitoring['node_exporter'],
         )
 
     if 'frr_exporter' in monitoring:
         # Render frr_exporter service_file
         render(
             frr_exporter_service_file,
             'prometheus/frr_exporter.service.j2',
             monitoring['frr_exporter'],
         )
 
+    if 'blackbox_exporter' in monitoring:
+        # Render blackbox_exporter service_file
+        render(
+            blackbox_exporter_service_file,
+            'prometheus/blackbox_exporter.service.j2',
+            monitoring['blackbox_exporter'],
+        )
+        # Render blackbox_exporter config file
+        render(
+            '/run/blackbox_exporter/config.yml',
+            'prometheus/blackbox_exporter.yml.j2',
+            monitoring['blackbox_exporter'],
+        )
+
     return None
 
 
 def apply(monitoring):
     # Reload systemd manager configuration
     call('systemctl daemon-reload')
     if not monitoring or 'node_exporter' not in monitoring:
         call(f'systemctl stop {node_exporter_systemd_service}')
     if not monitoring or 'frr_exporter' not in monitoring:
         call(f'systemctl stop {frr_exporter_systemd_service}')
+    if not monitoring or 'blackbox_exporter' not in monitoring:
+        call(f'systemctl stop {blackbox_exporter_systemd_service}')
 
     if not monitoring:
         return
 
     if 'node_exporter' in monitoring:
         # we need to restart the service if e.g. the VRF name changed
         systemd_action = 'reload-or-restart'
         if 'node_exporter_restart_required' in monitoring:
             systemd_action = 'restart'
 
         call(f'systemctl {systemd_action} {node_exporter_systemd_service}')
 
     if 'frr_exporter' in monitoring:
         # we need to restart the service if e.g. the VRF name changed
         systemd_action = 'reload-or-restart'
         if 'frr_exporter_restart_required' in monitoring:
             systemd_action = 'restart'
 
         call(f'systemctl {systemd_action} {frr_exporter_systemd_service}')
 
+    if 'blackbox_exporter' in monitoring:
+        # we need to restart the service if e.g. the VRF name changed
+        systemd_action = 'reload-or-restart'
+        if 'blackbox_exporter_restart_required' in monitoring:
+            systemd_action = 'restart'
+
+        call(f'systemctl {systemd_action} {blackbox_exporter_systemd_service}')
+
 
 if __name__ == '__main__':
     try:
         c = get_config()
         verify(c)
         generate(c)
         apply(c)
     except ConfigError as e:
         print(e)
         exit(1)