diff --git a/src/metrics.c b/src/metrics.c
new file mode 100644
index 0000000..8672807
--- /dev/null
+++ b/src/metrics.c
@@ -0,0 +1,44 @@
+/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
+
+ 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; version 2 dated June, 1991, or
+ (at your option) version 3 dated 29 June, 2007.
+
+ 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 .
+*/
+
+#include "dnsmasq.h"
+
+const char * metric_names[] = {
+ "dns_cache_inserted",
+ "dns_cache_live_freed",
+ "dns_queries_forwarded",
+ "dns_auth_answered",
+ "dns_local_answered",
+ "bootp",
+ "pxe",
+ "dhcp_ack",
+ "dhcp_decline",
+ "dhcp_discover",
+ "dhcp_inform",
+ "dhcp_nak",
+ "dhcp_offer",
+ "dhcp_release",
+ "dhcp_request",
+ "noanswer",
+ "leases_allocated_4",
+ "leases_pruned_4",
+ "leases_allocated_6",
+ "leases_pruned_6",
+};
+
+const char* get_metric_name(int i) {
+ return metric_names[i];
+}
diff --git a/src/metrics.h b/src/metrics.h
new file mode 100644
index 0000000..f13b8c8
--- /dev/null
+++ b/src/metrics.h
@@ -0,0 +1,27 @@
+// If you modify this list, please keep the labels in metrics.c in sync.
+enum {
+ METRIC_DNS_CACHE_INSERTED,
+ METRIC_DNS_CACHE_LIVE_FREED,
+ METRIC_DNS_QUERIES_FORWARDED,
+ METRIC_DNS_AUTH_ANSWERED,
+ METRIC_DNS_LOCAL_ANSWERED,
+ METRIC_BOOTP,
+ METRIC_PXE,
+ METRIC_DHCPACK,
+ METRIC_DHCPDECLINE,
+ METRIC_DHCPDISCOVER,
+ METRIC_DHCPINFORM,
+ METRIC_DHCPNAK,
+ METRIC_DHCPOFFER,
+ METRIC_DHCPRELEASE,
+ METRIC_DHCPREQUEST,
+ METRIC_NOANSWER,
+ METRIC_LEASES_ALLOCATED_4,
+ METRIC_LEASES_PRUNED_4,
+ METRIC_LEASES_ALLOCATED_6,
+ METRIC_LEASES_PRUNED_6,
+
+ __METRIC_MAX,
+};
+
+const char* get_metric_name(int);
diff --git a/src/ubus.c b/src/ubus.c
new file mode 100644
index 0000000..2b19593
--- /dev/null
+++ b/src/ubus.c
@@ -0,0 +1,105 @@
+/* dnsmasq is Copyright (c) 2000-2018 Simon Kelley
+
+ 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; version 2 dated June, 1991, or
+ (at your option) version 3 dated 29 June, 2007.
+
+ 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 .
+*/
+
+#include "dnsmasq.h"
+
+#ifdef HAVE_UBUS
+
+#include
+
+static struct ubus_context *ubus;
+static struct blob_buf b;
+
+static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg);
+static struct ubus_method ubus_object_methods[] = {
+ {.name = "metrics", .handler = ubus_handle_metrics},
+};
+
+static struct ubus_object_type ubus_object_type = UBUS_OBJECT_TYPE("dnsmasq", ubus_object_methods);
+
+static struct ubus_object ubus_object = {
+ .name = "dnsmasq",
+ .type = &ubus_object_type,
+ .methods = ubus_object_methods,
+ .n_methods = ARRAY_SIZE(ubus_object_methods),
+};
+
+void set_ubus_listeners()
+{
+ if (!ubus)
+ return;
+
+ poll_listen(ubus->sock.fd, POLLIN);
+ poll_listen(ubus->sock.fd, POLLERR);
+ poll_listen(ubus->sock.fd, POLLHUP);
+}
+
+void check_ubus_listeners()
+{
+ if (!ubus) {
+ ubus = ubus_connect(NULL);
+ if (!ubus)
+ return;
+ ubus_add_object(ubus, &ubus_object);
+ }
+
+ if (poll_check(ubus->sock.fd, POLLIN))
+ ubus_handle_event(ubus);
+
+ if (poll_check(ubus->sock.fd, POLLHUP)) {
+ ubus_free(ubus);
+ ubus = NULL;
+ }
+}
+
+
+static int ubus_handle_metrics(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ blob_buf_init(&b, 0);
+
+ for(int i=0; i < __METRIC_MAX; i++) {
+ blobmsg_add_u32(&b, get_metric_name(i), daemon->metrics[i]);
+ }
+
+ ubus_send_reply(ctx, req, b.head);
+
+ return 0;
+}
+
+void ubus_event_bcast(const char *type, const char *mac, const char *ip, const char *name, const char *interface)
+{
+ if (!ubus || !ubus_object.has_subscribers)
+ return;
+
+ blob_buf_init(&b, 0);
+ if (mac)
+ blobmsg_add_string(&b, "mac", mac);
+ if (ip)
+ blobmsg_add_string(&b, "ip", ip);
+ if (name)
+ blobmsg_add_string(&b, "name", name);
+ if (interface)
+ blobmsg_add_string(&b, "interface", interface);
+
+ ubus_notify(ubus, &ubus_object, type, b.head, -1);
+}
+
+
+#endif /* HAVE_UBUS */