To give visibility into DNS cache.
Either +yes+ or +no+, shows if the variable can be changed while running.
If +no+, the variable can be changed only boot-time.
+==== SHOW DNS_HOSTS ====
+
+Show hostnames in DNS cache.
+
+hostname::
+ Host name.
+
+ttl::
+ How meny seconds until next lookup.
+
+addrs::
+ Comma separated list of addresses.
+
+==== SHOW DNS_ZONES ====
+
+Show DNS zones in cache.
+
+zonename::
+ Zone name.
+
+serial::
+ Current serial.
+
+count::
+ Hostnames belonging to this zone.
+
+
=== PROCESS CONTROLLING COMMANDS ===
==== PAUSE [db]; ====
struct DNSContext;
struct DNSToken;
+struct addrinfo;
typedef void (*adns_callback_f)(void *arg, const struct sockaddr *sa, int salen);
void adns_info(struct DNSContext *ctx, int *names, int *zones, int *queries, int *pending);
+typedef void (*adns_walk_name_f)(void *arg, const char *name, const struct addrinfo *ai, usec_t ttl);
+typedef void (*adns_walk_zone_f)(void *arg, const char *name, uint32_t serial, int nhosts);
+
+void adns_walk_names(struct DNSContext *ctx, adns_walk_name_f cb, void *arg);
+void adns_walk_zones(struct DNSContext *ctx, adns_walk_zone_f cb, void *arg);
#include "bouncer.h"
#include <usual/regex.h>
+#include <usual/netdb.h>
/* regex elements */
#define WS0 "[ \t\n\r]*"
return true;
}
+/* Command: SHOW DNS_HOSTS */
+
+static void dns_name_cb(void *arg, const char *name, const struct addrinfo *ai, usec_t ttl)
+{
+ PktBuf *buf = arg;
+ char *s, *end;
+ char adrs[1024];
+ usec_t now = get_cached_time();
+
+ end = adrs + sizeof(adrs) - 2;
+ for (s = adrs; ai && s < end; ai = ai->ai_next) {
+ if (s != adrs)
+ *s++ = ',';
+ sa2str(ai->ai_addr, s, end - s);
+ s += strlen(s);
+ }
+ *s = 0;
+
+ pktbuf_write_DataRow(buf, "sqs", name, (ttl - now) / USEC, adrs);
+}
+
+static bool admin_show_dns_hosts(PgSocket *admin, const char *arg)
+{
+ PktBuf *buf;
+
+ buf = pktbuf_dynamic(256);
+ if (!buf) {
+ admin_error(admin, "no mem");
+ return true;
+ }
+ pktbuf_write_RowDescription(buf, "sqs", "hostname", "ttl", "addrs");
+ adns_walk_names(adns, dns_name_cb, buf);
+ admin_flush(admin, buf, "SHOW");
+ return true;
+}
+
+/* Command: SHOW DNS_ZONES */
+
+static void dns_zone_cb(void *arg, const char *name, uint32_t serial, int nhosts)
+{
+ PktBuf *buf = arg;
+ pktbuf_write_DataRow(buf, "sqi", name, (uint64_t)serial, nhosts);
+}
+
+static bool admin_show_dns_zones(PgSocket *admin, const char *arg)
+{
+ PktBuf *buf;
+
+ buf = pktbuf_dynamic(256);
+ if (!buf) {
+ admin_error(admin, "no mem");
+ return true;
+ }
+ pktbuf_write_RowDescription(buf, "sqi", "zonename", "serial", "count");
+ adns_walk_zones(adns, dns_zone_cb, buf);
+ admin_flush(admin, buf, "SHOW");
+ return true;
+}
+
+/* Command: SHOW CONFIG */
+
static void show_one_param(void *arg, const char *name, const char *val, bool reloadable)
{
PktBuf *buf = arg;
reloadable ? "yes" : "no");
}
-/* Command: SHOW CONFIG */
static bool admin_show_config(PgSocket *admin, const char *arg)
{
PktBuf *buf;
"D\n\tSHOW HELP|CONFIG|DATABASES"
"|POOLS|CLIENTS|SERVERS|VERSION\n"
"\tSHOW STATS|FDS|SOCKETS|ACTIVE_SOCKETS|LISTS|MEM\n"
+ "\tSHOW DNS_HOSTS|DNS_ZONES\n"
"\tSET key = arg\n"
"\tRELOAD\n"
"\tPAUSE [<db>]\n"
{"version", admin_show_version},
{"totals", admin_show_totals},
{"mem", admin_show_mem},
+ {"dns_hosts", admin_show_dns_hosts},
+ {"dns_zones", admin_show_dns_zones},
{NULL, NULL}
};
/* zone name serial */
struct DNSZone {
- struct List lnode; /* DNSContext->zone_list */
- struct AANode tnode; /* DNSContext->zone_tree */
+ struct List lnode; /* DNSContext->zone_list */
+ struct AANode tnode; /* DNSContext->zone_tree */
- struct List host_list; /* DNSRequest->znode */
+ struct StatList host_list; /* DNSRequest->znode */
const char *zonename;
uint32_t serial;
if (n) {
/* already exists */
z = container_of(n, struct DNSZone, tnode);
- list_append(&z->host_list, &req->znode);
+ statlist_append(&z->host_list, &req->znode);
return;
}
free(z);
return;
}
- list_init(&z->host_list);
+ statlist_init(&z->host_list, "host_list");
list_init(&z->lnode);
/* link */
aatree_insert(&ctx->zone_tree, (uintptr_t)z->zonename, &z->tnode);
list_append(&ctx->zone_list, &z->lnode);
- list_append(&z->host_list, &req->znode);
+ statlist_append(&z->host_list, &req->znode);
}
static void zone_timer(int fd, short flg, void *arg)
{
struct List *el;
struct DNSRequest *req;
- list_for_each(el, &z->host_list) {
+ statlist_for_each(el, &z->host_list) {
req = container_of(el, struct DNSRequest, znode);
if (!req->done)
continue;
}
}
+/*
+ * Cache walkers
+ */
+
+struct WalkInfo {
+ adns_walk_name_f name_cb;
+ adns_walk_zone_f zone_cb;
+ void *arg;
+};
+
+static void walk_name(struct AANode *n, void *arg)
+{
+ struct WalkInfo *w = arg;
+ struct DNSRequest *req = container_of(n, struct DNSRequest, node);
+
+ w->name_cb(w->arg, req->name, req->result, req->res_ttl);
+}
+
+static void walk_zone(struct AANode *n, void *arg)
+{
+ struct WalkInfo *w = arg;
+ struct DNSZone *z = container_of(n, struct DNSZone, tnode);
+
+ w->zone_cb(w->arg, z->zonename, z->serial, statlist_count(&z->host_list));
+}
+
+void adns_walk_names(struct DNSContext *ctx, adns_walk_name_f cb, void *arg)
+{
+ struct WalkInfo w;
+ w.name_cb = cb;
+ w.arg = arg;
+ aatree_walk(&ctx->req_tree, AA_WALK_IN_ORDER, walk_name, &w);
+}
+
+void adns_walk_zones(struct DNSContext *ctx, adns_walk_zone_f cb, void *arg)
+{
+ struct WalkInfo w;
+ w.zone_cb = cb;
+ w.arg = arg;
+ aatree_walk(&ctx->zone_tree, AA_WALK_IN_ORDER, walk_zone, &w);
+}
+