mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-12 21:07:43 +02:00
Merge branch 'master' into xfr-tsig
This commit is contained in:
+235
-105
@@ -62,84 +62,232 @@
|
||||
#include "sldns/wire2str.h"
|
||||
#include "sldns/str2wire.h"
|
||||
|
||||
static void spool_txt_printf(struct config_strlist_head* txt,
|
||||
const char* format, ...) ATTR_FORMAT(printf, 2, 3);
|
||||
|
||||
/** Append to strlist at end, and log error if out of memory. */
|
||||
static void
|
||||
spool_txt_string(struct config_strlist_head* txt, char* str)
|
||||
{
|
||||
if(!cfg_strlist_append(txt, strdup(str))) {
|
||||
log_err("out of memory in spool text");
|
||||
}
|
||||
}
|
||||
|
||||
/** Spool txt to spool list. */
|
||||
static void
|
||||
spool_txt_vmsg(struct config_strlist_head* txt, const char* format,
|
||||
va_list args)
|
||||
{
|
||||
char msg[65535];
|
||||
vsnprintf(msg, sizeof(msg), format, args);
|
||||
spool_txt_string(txt, msg);
|
||||
}
|
||||
|
||||
/** Print item to spool list. On alloc failure the list is as before. */
|
||||
static void
|
||||
spool_txt_printf(struct config_strlist_head* txt, const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
spool_txt_vmsg(txt, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/** dump one rrset zonefile line */
|
||||
static int
|
||||
dump_rrset_line(RES* ssl, struct ub_packed_rrset_key* k, time_t now, size_t i)
|
||||
static void
|
||||
dump_rrset_line(struct config_strlist_head* txt, struct ub_packed_rrset_key* k,
|
||||
time_t now, size_t i)
|
||||
{
|
||||
char s[65535];
|
||||
if(!packed_rr_to_string(k, i, now, s, sizeof(s))) {
|
||||
return ssl_printf(ssl, "BADRR\n");
|
||||
spool_txt_string(txt, "BADRR\n");
|
||||
return;
|
||||
}
|
||||
return ssl_printf(ssl, "%s", s);
|
||||
spool_txt_string(txt, s);
|
||||
}
|
||||
|
||||
/** dump rrset key and data info */
|
||||
static int
|
||||
dump_rrset(RES* ssl, struct ub_packed_rrset_key* k,
|
||||
static void
|
||||
dump_rrset(struct config_strlist_head* txt, struct ub_packed_rrset_key* k,
|
||||
struct packed_rrset_data* d, time_t now)
|
||||
{
|
||||
size_t i;
|
||||
/* rd lock held by caller */
|
||||
if(!k || !d) return 1;
|
||||
if(k->id == 0) return 1; /* deleted */
|
||||
if(d->ttl < now) return 1; /* expired */
|
||||
if(!k || !d) return;
|
||||
if(k->id == 0) return; /* deleted */
|
||||
if(d->ttl < now) return; /* expired */
|
||||
|
||||
/* meta line */
|
||||
if(!ssl_printf(ssl, ";rrset%s " ARG_LL "d %u %u %d %d\n",
|
||||
spool_txt_printf(txt, ";rrset%s " ARG_LL "d %u %u %d %d\n",
|
||||
(k->rk.flags & PACKED_RRSET_NSEC_AT_APEX)?" nsec_apex":"",
|
||||
(long long)(d->ttl - now),
|
||||
(unsigned)d->count, (unsigned)d->rrsig_count,
|
||||
(int)d->trust, (int)d->security
|
||||
))
|
||||
return 0;
|
||||
);
|
||||
for(i=0; i<d->count + d->rrsig_count; i++) {
|
||||
if(!dump_rrset_line(ssl, k, now, i))
|
||||
dump_rrset_line(txt, k, now, i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Spool strlist to the output. */
|
||||
static int
|
||||
spool_strlist(RES* ssl, struct config_strlist* list)
|
||||
{
|
||||
struct config_strlist* s;
|
||||
for(s=list; s; s=s->next) {
|
||||
if(!ssl_printf(ssl, "%s", s->str))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump lruhash rrset cache */
|
||||
/** dump lruhash cache and call callback for every item. */
|
||||
static int
|
||||
dump_rrset_lruhash(RES* ssl, struct lruhash* h, time_t now)
|
||||
dump_lruhash(struct lruhash* table,
|
||||
void (*func)(struct lruhash_entry*, struct config_strlist_head*, void*),
|
||||
RES* ssl, void* arg)
|
||||
{
|
||||
struct lruhash_entry* e;
|
||||
/* lruhash already locked by caller */
|
||||
/* walk in order of lru; best first */
|
||||
for(e=h->lru_start; e; e = e->lru_next) {
|
||||
lock_rw_rdlock(&e->lock);
|
||||
if(!dump_rrset(ssl, (struct ub_packed_rrset_key*)e->key,
|
||||
(struct packed_rrset_data*)e->data, now)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
int just_started = 1;
|
||||
int not_done = 1;
|
||||
hashvalue_type hash;
|
||||
size_t num = 0; /* number of entries processed. */
|
||||
size_t max = 2; /* number of entries after which it unlocks. */
|
||||
struct config_strlist_head txt; /* Text strings spooled. */
|
||||
memset(&txt, 0, sizeof(txt));
|
||||
|
||||
while(not_done) {
|
||||
size_t i; /* hash bin. */
|
||||
/* Process a number of items. */
|
||||
num = 0;
|
||||
lock_quick_lock(&table->lock);
|
||||
if(just_started) {
|
||||
i = 0;
|
||||
} else {
|
||||
i = hash&table->size_mask;
|
||||
}
|
||||
while(num < max) {
|
||||
/* Process bin. */
|
||||
int found = 0;
|
||||
size_t num_bin = 0;
|
||||
struct lruhash_bin* bin = &table->array[i];
|
||||
struct lruhash_entry* e;
|
||||
lock_quick_lock(&bin->lock);
|
||||
for(e = bin->overflow_list; e; e = e->overflow_next) {
|
||||
/* Entry e is locked by the func. */
|
||||
func(e, &txt, arg);
|
||||
num_bin++;
|
||||
}
|
||||
lock_quick_unlock(&bin->lock);
|
||||
/* This addition of bin number of entries may take
|
||||
* it over the max. */
|
||||
num += num_bin;
|
||||
|
||||
/* Move to next bin. */
|
||||
/* Find one with an entry, with a hash value, so we
|
||||
* can continue from the hash value. The hash value
|
||||
* can be indexed also if the array changes size. */
|
||||
i++;
|
||||
while(i < table->size) {
|
||||
bin = &table->array[i];
|
||||
lock_quick_lock(&bin->lock);
|
||||
if(bin->overflow_list) {
|
||||
hash = bin->overflow_list->hash;
|
||||
lock_quick_unlock(&bin->lock);
|
||||
found = 1;
|
||||
just_started = 0;
|
||||
break;
|
||||
}
|
||||
lock_quick_unlock(&bin->lock);
|
||||
i++;
|
||||
}
|
||||
if(!found) {
|
||||
not_done = 0;
|
||||
lock_quick_unlock(&table->lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
lock_quick_unlock(&table->lock);
|
||||
/* Print the spooled items, that are collected while the
|
||||
* locks are locked. The print happens while they are not
|
||||
* locked. */
|
||||
if(txt.first) {
|
||||
if(!spool_strlist(ssl, txt.first)) {
|
||||
config_delstrlist(txt.first);
|
||||
return 0;
|
||||
}
|
||||
config_delstrlist(txt.first);
|
||||
memset(&txt, 0, sizeof(txt));
|
||||
}
|
||||
}
|
||||
/* Print the final spooled items. */
|
||||
if(txt.first) {
|
||||
if(!spool_strlist(ssl, txt.first)) {
|
||||
config_delstrlist(txt.first);
|
||||
return 0;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
config_delstrlist(txt.first);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump slabhash cache and call callback for every item. */
|
||||
static int
|
||||
dump_slabhash(struct slabhash* sh,
|
||||
void (*func)(struct lruhash_entry*, struct config_strlist_head*, void*),
|
||||
RES* ssl, void* arg)
|
||||
{
|
||||
/* Process a number of items at a time, then unlock the cache,
|
||||
* so that ordinary processing can continue. Keep an iteration marker
|
||||
* to continue the loop. That means the cache can change, items
|
||||
* could be inserted and deleted. And, for example, the hash table
|
||||
* can grow. */
|
||||
size_t slab;
|
||||
for(slab=0; slab<sh->size; slab++) {
|
||||
if(!dump_lruhash(sh->array[slab], func, ssl, arg))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Struct for dump information. */
|
||||
struct dump_info {
|
||||
/** The worker. */
|
||||
struct worker* worker;
|
||||
/** The printout connection. */
|
||||
RES* ssl;
|
||||
};
|
||||
|
||||
/** Dump the rrset cache entry */
|
||||
static void
|
||||
dump_rrset_entry(struct lruhash_entry* e, struct config_strlist_head* txt,
|
||||
void* arg)
|
||||
{
|
||||
struct dump_info* dump_info = (struct dump_info*)arg;
|
||||
lock_rw_rdlock(&e->lock);
|
||||
dump_rrset(txt, (struct ub_packed_rrset_key*)e->key,
|
||||
(struct packed_rrset_data*)e->data,
|
||||
*dump_info->worker->env.now);
|
||||
lock_rw_unlock(&e->lock);
|
||||
}
|
||||
|
||||
/** dump rrset cache */
|
||||
static int
|
||||
dump_rrset_cache(RES* ssl, struct worker* worker)
|
||||
{
|
||||
struct rrset_cache* r = worker->env.rrset_cache;
|
||||
size_t slab;
|
||||
struct dump_info dump_info;
|
||||
dump_info.worker = worker;
|
||||
dump_info.ssl = ssl;
|
||||
if(!ssl_printf(ssl, "START_RRSET_CACHE\n")) return 0;
|
||||
for(slab=0; slab<r->table.size; slab++) {
|
||||
lock_quick_lock(&r->table.array[slab]->lock);
|
||||
if(!dump_rrset_lruhash(ssl, r->table.array[slab],
|
||||
*worker->env.now)) {
|
||||
lock_quick_unlock(&r->table.array[slab]->lock);
|
||||
return 0;
|
||||
}
|
||||
lock_quick_unlock(&r->table.array[slab]->lock);
|
||||
}
|
||||
if(!dump_slabhash(&r->table, &dump_rrset_entry, ssl, &dump_info))
|
||||
return 0;
|
||||
return ssl_printf(ssl, "END_RRSET_CACHE\n");
|
||||
}
|
||||
|
||||
/** dump message to rrset reference */
|
||||
static int
|
||||
dump_msg_ref(RES* ssl, struct ub_packed_rrset_key* k)
|
||||
static void
|
||||
dump_msg_ref(struct config_strlist_head* txt, struct ub_packed_rrset_key* k)
|
||||
{
|
||||
char* nm, *tp, *cl;
|
||||
nm = sldns_wire2str_dname(k->rk.dname, k->rk.dname_len);
|
||||
@@ -149,30 +297,25 @@ dump_msg_ref(RES* ssl, struct ub_packed_rrset_key* k)
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return ssl_printf(ssl, "BADREF\n");
|
||||
}
|
||||
if(!ssl_printf(ssl, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags)) {
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return 0;
|
||||
spool_txt_string(txt, "BADREF\n");
|
||||
return;
|
||||
}
|
||||
spool_txt_printf(txt, "%s %s %s %d\n", nm, cl, tp, (int)k->rk.flags);
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** dump message entry */
|
||||
static int
|
||||
dump_msg(RES* ssl, struct query_info* k, struct reply_info* d, time_t now)
|
||||
static void
|
||||
dump_msg(struct config_strlist_head* txt, struct query_info* k,
|
||||
struct reply_info* d, time_t now)
|
||||
{
|
||||
size_t i;
|
||||
char* nm, *tp, *cl;
|
||||
if(!k || !d) return 1;
|
||||
if(d->ttl < now) return 1; /* expired */
|
||||
|
||||
if(!k || !d) return;
|
||||
if(d->ttl < now) return; /* expired */
|
||||
|
||||
nm = sldns_wire2str_dname(k->qname, k->qname_len);
|
||||
tp = sldns_wire2str_type(k->qtype);
|
||||
cl = sldns_wire2str_class(k->qclass);
|
||||
@@ -180,45 +323,35 @@ dump_msg(RES* ssl, struct query_info* k, struct reply_info* d, time_t now)
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return 1; /* skip this entry */
|
||||
return; /* skip this entry */
|
||||
}
|
||||
if(!rrset_array_lock(d->ref, d->rrset_count, now)) {
|
||||
/* rrsets have timed out or do not exist */
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
return 1; /* skip this entry */
|
||||
return; /* skip this entry */
|
||||
}
|
||||
|
||||
|
||||
/* meta line */
|
||||
if(!ssl_printf(ssl, "msg %s %s %s %d %d " ARG_LL "d %d %u %u %u %d %s\n",
|
||||
nm, cl, tp,
|
||||
(int)d->flags, (int)d->qdcount,
|
||||
(long long)(d->ttl-now), (int)d->security,
|
||||
(unsigned)d->an_numrrsets,
|
||||
(unsigned)d->ns_numrrsets,
|
||||
(unsigned)d->ar_numrrsets,
|
||||
(int)d->reason_bogus,
|
||||
d->reason_bogus_str?d->reason_bogus_str:"")) {
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
return 0;
|
||||
}
|
||||
spool_txt_printf(txt,
|
||||
"msg %s %s %s %d %d " ARG_LL "d %d %u %u %u %d %s\n",
|
||||
nm, cl, tp,
|
||||
(int)d->flags, (int)d->qdcount,
|
||||
(long long)(d->ttl-now), (int)d->security,
|
||||
(unsigned)d->an_numrrsets,
|
||||
(unsigned)d->ns_numrrsets,
|
||||
(unsigned)d->ar_numrrsets,
|
||||
(int)d->reason_bogus,
|
||||
d->reason_bogus_str?d->reason_bogus_str:"");
|
||||
free(nm);
|
||||
free(tp);
|
||||
free(cl);
|
||||
|
||||
for(i=0; i<d->rrset_count; i++) {
|
||||
if(!dump_msg_ref(ssl, d->rrsets[i])) {
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
return 0;
|
||||
}
|
||||
dump_msg_ref(txt, d->rrsets[i]);
|
||||
}
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** copy msg to worker pad */
|
||||
@@ -247,49 +380,40 @@ copy_msg(struct regional* region, struct lruhash_entry* e,
|
||||
return (*k)->qname != NULL;
|
||||
}
|
||||
|
||||
/** dump lruhash msg cache */
|
||||
static int
|
||||
dump_msg_lruhash(RES* ssl, struct worker* worker, struct lruhash* h)
|
||||
/** Dump the msg entry. */
|
||||
static void
|
||||
dump_msg_entry(struct lruhash_entry* e, struct config_strlist_head* txt,
|
||||
void* arg)
|
||||
{
|
||||
struct lruhash_entry* e;
|
||||
struct dump_info* dump_info = (struct dump_info*)arg;
|
||||
struct query_info* k;
|
||||
struct reply_info* d;
|
||||
|
||||
/* lruhash already locked by caller */
|
||||
/* walk in order of lru; best first */
|
||||
for(e=h->lru_start; e; e = e->lru_next) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
lock_rw_rdlock(&e->lock);
|
||||
/* make copy of rrset in worker buffer */
|
||||
if(!copy_msg(worker->scratchpad, e, &k, &d)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
regional_free_all(dump_info->worker->scratchpad);
|
||||
/* Make copy of rrset in worker buffer. */
|
||||
lock_rw_rdlock(&e->lock);
|
||||
if(!copy_msg(dump_info->worker->scratchpad, e, &k, &d)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
/* release lock so we can lookup the rrset references
|
||||
* in the rrset cache */
|
||||
if(!dump_msg(ssl, k, d, *worker->env.now)) {
|
||||
return 0;
|
||||
}
|
||||
log_err("out of memory in dump_msg_entry");
|
||||
return;
|
||||
}
|
||||
return 1;
|
||||
lock_rw_unlock(&e->lock);
|
||||
/* Release lock so we can lookup the rrset references
|
||||
* in the rrset cache. */
|
||||
dump_msg(txt, k, d, *dump_info->worker->env.now);
|
||||
}
|
||||
|
||||
/** dump msg cache */
|
||||
static int
|
||||
dump_msg_cache(RES* ssl, struct worker* worker)
|
||||
{
|
||||
struct slabhash* sh = worker->env.msg_cache;
|
||||
size_t slab;
|
||||
struct dump_info dump_info;
|
||||
dump_info.worker = worker;
|
||||
dump_info.ssl = ssl;
|
||||
if(!ssl_printf(ssl, "START_MSG_CACHE\n")) return 0;
|
||||
for(slab=0; slab<sh->size; slab++) {
|
||||
lock_quick_lock(&sh->array[slab]->lock);
|
||||
if(!dump_msg_lruhash(ssl, worker, sh->array[slab])) {
|
||||
lock_quick_unlock(&sh->array[slab]->lock);
|
||||
return 0;
|
||||
}
|
||||
lock_quick_unlock(&sh->array[slab]->lock);
|
||||
}
|
||||
if(!dump_slabhash(worker->env.msg_cache, &dump_msg_entry, ssl,
|
||||
&dump_info))
|
||||
return 0;
|
||||
return ssl_printf(ssl, "END_MSG_CACHE\n");
|
||||
}
|
||||
|
||||
@@ -811,12 +935,18 @@ print_dp_main(RES* ssl, struct delegpt* dp, struct dns_msg* msg)
|
||||
struct ub_packed_rrset_key* k = msg->rep->rrsets[i];
|
||||
struct packed_rrset_data* d =
|
||||
(struct packed_rrset_data*)k->entry.data;
|
||||
struct config_strlist_head txt;
|
||||
memset(&txt, 0, sizeof(txt));
|
||||
if(d->security == sec_status_bogus) {
|
||||
if(!ssl_printf(ssl, "Address is BOGUS:\n"))
|
||||
return;
|
||||
}
|
||||
if(!dump_rrset(ssl, k, d, 0))
|
||||
dump_rrset(&txt, k, d, 0);
|
||||
if(!spool_strlist(ssl, txt.first)) {
|
||||
config_delstrlist(txt.first);
|
||||
return;
|
||||
}
|
||||
config_delstrlist(txt.first);
|
||||
}
|
||||
delegpt_count_ns(dp, &n_ns, &n_miss);
|
||||
delegpt_count_addr(dp, &n_addr, &n_res, &n_avail);
|
||||
|
||||
+335
@@ -101,6 +101,10 @@
|
||||
#ifdef USE_CACHEDB
|
||||
#include "cachedb/cachedb.h"
|
||||
#endif
|
||||
#ifdef CLIENT_SUBNET
|
||||
#include "edns-subnet/subnetmod.h"
|
||||
#include "edns-subnet/addrtree.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
@@ -1742,6 +1746,334 @@ do_view_datas_remove(struct daemon_remote* rc, RES* ssl, struct worker* worker,
|
||||
(void)ssl_printf(ssl, "removed %d datas\n", num);
|
||||
}
|
||||
|
||||
/** information for the domain search */
|
||||
struct cache_lookup_info {
|
||||
/** The connection to print on. */
|
||||
RES* ssl;
|
||||
/** The worker. */
|
||||
struct worker* worker;
|
||||
/** The domain, in wireformat. */
|
||||
uint8_t* nm;
|
||||
/** The length of nm. */
|
||||
size_t nmlen;
|
||||
};
|
||||
|
||||
#ifdef CLIENT_SUBNET
|
||||
static void addrtree_traverse_visit_node(struct addrnode* n, addrkey_t* addr,
|
||||
size_t addr_size, int is_ipv6, time_t now, struct query_info* q,
|
||||
void (*func)(struct query_info*, struct reply_info*, addrkey_t*,
|
||||
size_t, int, addrlen_t, int, time_t, void*), void* arg);
|
||||
|
||||
/** Lookup in subnet addrtree */
|
||||
static void
|
||||
cache_lookup_subnet_addrnode(struct query_info* q, struct reply_info* d,
|
||||
addrkey_t* addr, size_t addr_size, int is_ipv6, addrlen_t scope,
|
||||
int only_match_scope_zero, time_t ttl, void* arg)
|
||||
{
|
||||
size_t i;
|
||||
char s[65535], tp[32], cl[32], rc[32], fg[32], astr[64];
|
||||
struct cache_lookup_info* inf = (struct cache_lookup_info*)arg;
|
||||
if(is_ipv6) {
|
||||
if(addr_size < 16 || inet_ntop(AF_INET6, addr, astr,
|
||||
sizeof(astr)) == NULL)
|
||||
snprintf(astr, sizeof(astr), "(inet6ntoperror)");
|
||||
} else {
|
||||
if(addr_size < 4 || inet_ntop(AF_INET, addr, astr,
|
||||
sizeof(astr)) == NULL)
|
||||
snprintf(astr, sizeof(astr), "(inetntoperror)");
|
||||
}
|
||||
sldns_wire2str_dname_buf(q->qname, q->qname_len, s, sizeof(s));
|
||||
sldns_wire2str_type_buf(q->qtype, tp, sizeof(tp));
|
||||
sldns_wire2str_class_buf(q->qclass, cl, sizeof(cl));
|
||||
sldns_wire2str_rcode_buf(FLAGS_GET_RCODE(d->flags),
|
||||
rc, sizeof(rc));
|
||||
snprintf(fg, sizeof(fg), "%s%s%s%s%s%s%s%s",
|
||||
((d->flags&BIT_QR)?" QR":""),
|
||||
((d->flags&BIT_AA)?" AA":""),
|
||||
((d->flags&BIT_TC)?" TC":""),
|
||||
((d->flags&BIT_RD)?" RD":""),
|
||||
((d->flags&BIT_RA)?" RA":""),
|
||||
((d->flags&BIT_Z)?" Z":""),
|
||||
((d->flags&BIT_AD)?" AD":""),
|
||||
((d->flags&BIT_CD)?" CD":""));
|
||||
if(!rrset_array_lock(d->ref, d->rrset_count,
|
||||
*inf->worker->env.now)) {
|
||||
/* rrsets have timed out or do not exist */
|
||||
return;
|
||||
}
|
||||
if(!ssl_printf(inf->ssl, "subnet %s/%d%s %s %s %s " ARG_LL "d\n", astr,
|
||||
(int)scope, (only_match_scope_zero?" scope_zero":""),
|
||||
s, cl, tp, (long long)(ttl-*inf->worker->env.now))) {
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
return;
|
||||
}
|
||||
ssl_printf(inf->ssl,
|
||||
"subnet msg %s %s %s%s %s %d %d " ARG_LL "d %d %u %u %u %d %s\n",
|
||||
s, cl, tp, fg, rc,
|
||||
(int)d->flags, (int)d->qdcount,
|
||||
(long long)(d->ttl-*inf->worker->env.now),
|
||||
(int)d->security,
|
||||
(unsigned)d->an_numrrsets,
|
||||
(unsigned)d->ns_numrrsets,
|
||||
(unsigned)d->ar_numrrsets,
|
||||
(int)d->reason_bogus,
|
||||
d->reason_bogus_str?d->reason_bogus_str:"");
|
||||
for(i=0; i<d->rrset_count; i++) {
|
||||
struct ub_packed_rrset_key* rk = d->rrsets[i];
|
||||
struct packed_rrset_data* rd = (struct packed_rrset_data*)rk->entry.data;
|
||||
size_t j;
|
||||
for(j=0; j<rd->count + rd->rrsig_count; j++) {
|
||||
if(!packed_rr_to_string(rk, j,
|
||||
*inf->worker->env.now, s, sizeof(s))) {
|
||||
ssl_printf(inf->ssl, "BADRR\n");
|
||||
} else {
|
||||
ssl_printf(inf->ssl, "%s", s);
|
||||
}
|
||||
}
|
||||
}
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
ssl_printf(inf->ssl, "\n");
|
||||
}
|
||||
|
||||
/** Visit an edge in subnet addrtree traverse */
|
||||
static void
|
||||
addrtree_traverse_visit_edge(struct addredge* edge, addrkey_t* addr,
|
||||
size_t addr_size, int is_ipv6, time_t now, struct query_info* q,
|
||||
void (*func)(struct query_info*, struct reply_info*, addrkey_t*,
|
||||
size_t, int, addrlen_t, int, time_t, void*), void* arg)
|
||||
{
|
||||
size_t n;
|
||||
addrlen_t addrlen;
|
||||
if(!edge || !edge->node)
|
||||
return;
|
||||
addrlen = edge->len;
|
||||
/* ceil() */
|
||||
n = (size_t)((addrlen / KEYWIDTH) + ((addrlen % KEYWIDTH != 0)?1:0));
|
||||
if(n > addr_size)
|
||||
n = addr_size;
|
||||
memset(addr, 0, addr_size);
|
||||
memcpy(addr, edge->str, n);
|
||||
addrtree_traverse_visit_node(edge->node, addr, addr_size, is_ipv6,
|
||||
now, q, func, arg);
|
||||
}
|
||||
|
||||
/** Visit a node in subnet addrtree traverse */
|
||||
static void
|
||||
addrtree_traverse_visit_node(struct addrnode* n, addrkey_t* addr,
|
||||
size_t addr_size, int is_ipv6, time_t now, struct query_info* q,
|
||||
void (*func)(struct query_info*, struct reply_info*, addrkey_t*,
|
||||
size_t, int, addrlen_t, int, time_t, void*), void* arg)
|
||||
{
|
||||
/* If this node has data, and not expired. */
|
||||
if(n->elem && n->ttl >= now) {
|
||||
func(q, (struct reply_info*)n->elem, addr, addr_size, is_ipv6,
|
||||
n->scope, n->only_match_scope_zero, n->ttl, arg);
|
||||
}
|
||||
/* Traverse edges. */
|
||||
addrtree_traverse_visit_edge(n->edge[0], addr, addr_size, is_ipv6,
|
||||
now, q, func, arg);
|
||||
addrtree_traverse_visit_edge(n->edge[1], addr, addr_size, is_ipv6,
|
||||
now, q, func, arg);
|
||||
}
|
||||
|
||||
/** Traverse subnet addrtree */
|
||||
static void
|
||||
addrtree_traverse(struct addrtree* tree, int is_ipv6, time_t now,
|
||||
struct query_info* q,
|
||||
void (*func)(struct query_info*, struct reply_info*, addrkey_t*,
|
||||
size_t, int, addrlen_t, int, time_t, void*), void* arg)
|
||||
{
|
||||
uint8_t addr[16]; /* Large enough for IPv4 and IPv6. */
|
||||
memset(addr, 0, sizeof(addr));
|
||||
addrtree_traverse_visit_node(tree->root, (addrkey_t*)addr,
|
||||
sizeof(addr), is_ipv6, now, q, func, arg);
|
||||
}
|
||||
|
||||
/** Lookup cache_lookup for subnet content. */
|
||||
static void
|
||||
cache_lookup_subnet_msg(struct lruhash_entry* e, void* arg)
|
||||
{
|
||||
struct cache_lookup_info* inf = (struct cache_lookup_info*)arg;
|
||||
struct msgreply_entry *k = (struct msgreply_entry*)e->key;
|
||||
struct subnet_msg_cache_data* d =
|
||||
(struct subnet_msg_cache_data*)e->data;
|
||||
if(!dname_subdomain_c(k->key.qname, inf->nm))
|
||||
return;
|
||||
|
||||
if(d->tree4) {
|
||||
addrtree_traverse(d->tree4, 0, *inf->worker->env.now, &k->key,
|
||||
&cache_lookup_subnet_addrnode, inf);
|
||||
}
|
||||
if(d->tree6) {
|
||||
addrtree_traverse(d->tree6, 1, *inf->worker->env.now, &k->key,
|
||||
&cache_lookup_subnet_addrnode, inf);
|
||||
}
|
||||
}
|
||||
#endif /* CLIENT_SUBNET */
|
||||
|
||||
static void
|
||||
cache_lookup_rrset(struct lruhash_entry* e, void* arg)
|
||||
{
|
||||
struct cache_lookup_info* inf = (struct cache_lookup_info*)arg;
|
||||
struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key;
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)e->data;
|
||||
if(*inf->worker->env.now < d->ttl &&
|
||||
k->id != 0 && /* not deleted */
|
||||
dname_subdomain_c(k->rk.dname, inf->nm)) {
|
||||
size_t i;
|
||||
for(i=0; i<d->count + d->rrsig_count; i++) {
|
||||
char s[65535];
|
||||
if(!packed_rr_to_string(k, i, *inf->worker->env.now,
|
||||
s, sizeof(s))) {
|
||||
ssl_printf(inf->ssl, "BADRR\n");
|
||||
return;
|
||||
}
|
||||
ssl_printf(inf->ssl, "%s", s);
|
||||
}
|
||||
ssl_printf(inf->ssl, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cache_lookup_msg(struct lruhash_entry* e, void* arg)
|
||||
{
|
||||
struct cache_lookup_info* inf = (struct cache_lookup_info*)arg;
|
||||
struct msgreply_entry* k = (struct msgreply_entry*)e->key;
|
||||
struct reply_info* d = (struct reply_info*)e->data;
|
||||
if(*inf->worker->env.now < d->ttl &&
|
||||
dname_subdomain_c(k->key.qname, inf->nm)) {
|
||||
size_t i;
|
||||
char s[65535], tp[32], cl[32], rc[32], fg[32];
|
||||
sldns_wire2str_dname_buf(k->key.qname, k->key.qname_len,
|
||||
s, sizeof(s));
|
||||
sldns_wire2str_type_buf(k->key.qtype, tp, sizeof(tp));
|
||||
sldns_wire2str_class_buf(k->key.qclass, cl, sizeof(cl));
|
||||
sldns_wire2str_rcode_buf(FLAGS_GET_RCODE(d->flags),
|
||||
rc, sizeof(rc));
|
||||
snprintf(fg, sizeof(fg), "%s%s%s%s%s%s%s%s",
|
||||
((d->flags&BIT_QR)?" QR":""),
|
||||
((d->flags&BIT_AA)?" AA":""),
|
||||
((d->flags&BIT_TC)?" TC":""),
|
||||
((d->flags&BIT_RD)?" RD":""),
|
||||
((d->flags&BIT_RA)?" RA":""),
|
||||
((d->flags&BIT_Z)?" Z":""),
|
||||
((d->flags&BIT_AD)?" AD":""),
|
||||
((d->flags&BIT_CD)?" CD":""));
|
||||
if(!rrset_array_lock(d->ref, d->rrset_count,
|
||||
*inf->worker->env.now)) {
|
||||
/* rrsets have timed out or do not exist */
|
||||
return;
|
||||
}
|
||||
ssl_printf(inf->ssl,
|
||||
"msg %s %s %s%s %s %d %d " ARG_LL "d %d %u %u %u %d %s\n",
|
||||
s, cl, tp, fg, rc,
|
||||
(int)d->flags, (int)d->qdcount,
|
||||
(long long)(d->ttl-*inf->worker->env.now),
|
||||
(int)d->security,
|
||||
(unsigned)d->an_numrrsets,
|
||||
(unsigned)d->ns_numrrsets,
|
||||
(unsigned)d->ar_numrrsets,
|
||||
(int)d->reason_bogus,
|
||||
d->reason_bogus_str?d->reason_bogus_str:"");
|
||||
for(i=0; i<d->rrset_count; i++) {
|
||||
struct ub_packed_rrset_key* rk = d->rrsets[i];
|
||||
struct packed_rrset_data* rd = (struct packed_rrset_data*)rk->entry.data;
|
||||
size_t j;
|
||||
for(j=0; j<rd->count + rd->rrsig_count; j++) {
|
||||
if(!packed_rr_to_string(rk, j,
|
||||
*inf->worker->env.now, s, sizeof(s))) {
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
ssl_printf(inf->ssl, "BADRR\n");
|
||||
return;
|
||||
}
|
||||
ssl_printf(inf->ssl, "%s", s);
|
||||
}
|
||||
}
|
||||
rrset_array_unlock(d->ref, d->rrset_count);
|
||||
ssl_printf(inf->ssl, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/** perform cache search for domain */
|
||||
static void
|
||||
do_cache_lookup_domain(RES* ssl, struct worker* worker, uint8_t* nm,
|
||||
size_t nmlen)
|
||||
{
|
||||
#ifdef CLIENT_SUBNET
|
||||
int m;
|
||||
struct subnet_env* sn_env = NULL;
|
||||
#endif /* CLIENT_SUBNET */
|
||||
struct cache_lookup_info inf;
|
||||
inf.ssl = ssl;
|
||||
inf.worker = worker;
|
||||
inf.nm = nm;
|
||||
inf.nmlen = nmlen;
|
||||
|
||||
#ifdef CLIENT_SUBNET
|
||||
m = modstack_find(worker->env.modstack, "subnetcache");
|
||||
if(m != -1) sn_env = (struct subnet_env*)worker->env.modinfo[m];
|
||||
if(sn_env) {
|
||||
lock_rw_rdlock(&sn_env->biglock);
|
||||
slabhash_traverse(sn_env->subnet_msg_cache, 0,
|
||||
&cache_lookup_subnet_msg, &inf);
|
||||
lock_rw_unlock(&sn_env->biglock);
|
||||
}
|
||||
#endif /* CLIENT_SUBNET */
|
||||
|
||||
slabhash_traverse(&worker->env.rrset_cache->table, 0,
|
||||
&cache_lookup_rrset, &inf);
|
||||
slabhash_traverse(worker->env.msg_cache, 0, &cache_lookup_msg, &inf);
|
||||
}
|
||||
|
||||
/** cache lookup of domain */
|
||||
static void
|
||||
do_cache_lookup(RES* ssl, struct worker* worker, char* arg)
|
||||
{
|
||||
uint8_t nm[LDNS_MAX_DOMAINLEN+1];
|
||||
size_t nmlen;
|
||||
int status;
|
||||
char* s = arg, *next = NULL;
|
||||
int allow_long = 0;
|
||||
|
||||
if(arg[0] == '+' && arg[1] == 't' && (arg[2]==' ' || arg[2]=='\t')) {
|
||||
allow_long = 1;
|
||||
s = arg+2;
|
||||
}
|
||||
|
||||
/* Find the commandline arguments of domains. */
|
||||
while(s && *s != 0) {
|
||||
s = skipwhite(s);
|
||||
if(*s == 0)
|
||||
break;
|
||||
if(strchr(s, ' ') || strchr(s, '\t')) {
|
||||
char* sp = strchr(s, ' ');
|
||||
if(strchr(s, '\t') != 0 && strchr(s, '\t') < sp)
|
||||
sp = strchr(s, '\t');
|
||||
*sp = 0;
|
||||
next = sp+1;
|
||||
} else {
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
nmlen = sizeof(nm);
|
||||
status = sldns_str2wire_dname_buf(s, nm, &nmlen);
|
||||
if(status != 0) {
|
||||
ssl_printf(ssl, "error cannot parse name %s at %d: %s\n", s,
|
||||
LDNS_WIREPARSE_OFFSET(status),
|
||||
sldns_get_errorstr_parse(status));
|
||||
return;
|
||||
}
|
||||
if(!allow_long && dname_count_labels(nm) < 3) {
|
||||
ssl_printf(ssl, "error name too short: '%s'. Need example.com. or longer, short names take very long, use +t to allow them.\n", s);
|
||||
return;
|
||||
}
|
||||
|
||||
do_cache_lookup_domain(ssl, worker, nm, nmlen);
|
||||
|
||||
s = next;
|
||||
}
|
||||
}
|
||||
|
||||
/** cache lookup of nameservers */
|
||||
static void
|
||||
do_lookup(RES* ssl, struct worker* worker, char* arg)
|
||||
@@ -3615,6 +3947,9 @@ execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd,
|
||||
if(rc) distribute_cmd(rc, ssl, cmd);
|
||||
do_flush_requestlist(ssl, worker);
|
||||
return;
|
||||
} else if(cmdcmp(p, "cache_lookup", 12)) {
|
||||
do_cache_lookup(ssl, worker, skipwhite(p+12));
|
||||
return;
|
||||
} else if(cmdcmp(p, "lookup", 6)) {
|
||||
do_lookup(ssl, worker, skipwhite(p+6));
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user