Merge branch 'master' into xfr-tsig

This commit is contained in:
W.C.A. Wijngaards 2025-08-19 15:27:43 +02:00
commit 54175a4180
20 changed files with 1688 additions and 144 deletions

View file

@ -1200,7 +1200,7 @@ unitanchor.lo unitanchor.o: $(srcdir)/testcode/unitanchor.c config.h $(srcdir)/u
$(srcdir)/validator/val_anchor.h $(srcdir)/util/rbtree.h $(srcdir)/sldns/sbuffer.h $(srcdir)/sldns/rrdef.h
unitdname.lo unitdname.o: $(srcdir)/testcode/unitdname.c config.h $(srcdir)/util/log.h $(srcdir)/testcode/unitmain.h \
$(srcdir)/util/data/dname.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/sldns/sbuffer.h \
$(srcdir)/sldns/str2wire.h $(srcdir)/sldns/rrdef.h
$(srcdir)/sldns/str2wire.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/wire2str.h
unitlruhash.lo unitlruhash.o: $(srcdir)/testcode/unitlruhash.c config.h $(srcdir)/testcode/unitmain.h \
$(srcdir)/util/log.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/storage/slabhash.h
unitmain.lo unitmain.o: $(srcdir)/testcode/unitmain.c config.h $(srcdir)/sldns/rrdef.h $(srcdir)/sldns/keyraw.h \

View file

@ -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);

View file

@ -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;

View file

@ -1,3 +1,47 @@
15 August 2025: Wouter
- unbound-control cache_lookup +t allows tld and root names. And
subnet cache contents are printed.
- Fix cache_lookup subnet printout to wipe zero part of the prefix.
- Fix cache_lookup subnet print to not print messages without rrsets
and perform in-depth check on node in the addrtree.
14 August 2025: Wouter
- Fix to increase responsiveness of dump_cache.
- Fix to decouple file descriptor activity and cache lookups in
dump_cache.
13 August 2025: Wouter
- unbound-control cache_lookup <domains> prints the cached rrsets
and messages for those.
- Fix to remove debug from cache_lookup.
- Fix to unlock cache_lookup message for malformed records.
12 August 2025: Wouter
- Fix that unbound-control dump_cache releases the cache locks
every so often, so that the server stays responsive.
7 August 2025: Wouter
- Fix dname_str for printout of long names. Thanks to Jan Komissar
for the fix.
- Fix that edns-subnet failure to create a subquery errors as
servfail, and not formerror.
- Fix to whitespace in dname_str.
6 August 2025: Wouter
- Fix edns subnet, so that the subquery without subnet is stored in
global cache if the querier used 0.0.0.0/0 and the name and address
do not receive subnet treatment. If the name and address are
configured for subnet, it is stored in the subnet cache.
5 August 2025: Wouter
- Fix #1309: incorrectly reclaimed tcp handler can cause data
corruption and segfault.
- Fix to use assertions for consistency checks in #1309 reclaimed
tcp handlers.
1 August 2025: Wouter
- Fix testbound test program to accurately output packets from hex.
28 July 2025: Wouter
- Fix redis cachedb module gettimeofday init failure.

View file

@ -386,6 +386,18 @@ There are several commands that the server understands.
Not supported in remote Unbounds in multi-process operation.
@@UAHL@unbound-control.commands@cache_lookup@@ [``+t``] *names*
Print to stdout the RRsets and messages that are in the cache.
For every name listed the content at or under the name is printed.
Several names separated by spaces can be given, each is printed.
When subnetcache is enabled, also matching entries from the subnet
cache are printed.
The ``+t`` option allows tld and root names.
With it names like 'com' and '.' can be used, but it takes a lot of
effort to look up in the cache.
@@UAHL@unbound-control.commands@lookup@@ *name*
Print to stdout the name servers that would be used to look up the name
specified.

View file

@ -154,6 +154,21 @@ int ecs_whitelist_check(struct query_info* qinfo,
return 1;
sn_env = (struct subnet_env*)qstate->env->modinfo[id];
if(sq->is_subquery_nonsubnet) {
if(sq->is_subquery_scopezero) {
/* Check if the result can be stored in the global cache,
* this is okay if the address and name are not configured
* as subnet address and subnet zone. */
if(!ecs_is_whitelisted(sn_env->whitelist,
addr, addrlen, qinfo->qname, qinfo->qname_len,
qinfo->qclass)) {
verbose(VERB_ALGO, "subnet store subquery global, name and addr have no subnet treatment.");
qstate->no_cache_store = 0;
}
}
return 1;
}
/* Cache by default, might be disabled after parsing EDNS option
* received from nameserver. */
if(!iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)
@ -527,11 +542,12 @@ common_prefix(uint8_t *a, uint8_t *b, uint8_t net)
/**
* Create sub request that looks up the query.
* @param qstate: query state
* @param id: module id.
* @param sq: subnet qstate
* @return false on failure.
*/
static int
generate_sub_request(struct module_qstate *qstate, struct subnet_qstate* sq)
generate_sub_request(struct module_qstate *qstate, int id, struct subnet_qstate* sq)
{
struct module_qstate* subq = NULL;
uint16_t qflags = 0; /* OPCODE QUERY, no flags */
@ -557,10 +573,22 @@ generate_sub_request(struct module_qstate *qstate, struct subnet_qstate* sq)
}
if(subq) {
/* It is possible to access the subquery module state. */
struct subnet_qstate* subsq;
if(!subnet_new_qstate(subq, id)) {
verbose(VERB_ALGO, "Could not allocate new subnet qstate");
return 0;
}
subsq = (struct subnet_qstate*)subq->minfo[id];
subsq->is_subquery_nonsubnet = 1;
/* When the client asks 0.0.0.0/0 and the name is not treated
* as subnet, it is to be stored in the global cache.
* Store that the client asked for that, if so. */
if(sq->ecs_client_in.subnet_source_mask == 0 &&
edns_opt_list_find(qstate->edns_opts_front_in,
qstate->env->cfg->client_subnet_opcode)) {
subq->no_cache_store = 1;
subsq->is_subquery_scopezero = 1;
}
}
return 1;
@ -569,17 +597,18 @@ generate_sub_request(struct module_qstate *qstate, struct subnet_qstate* sq)
/**
* Perform the query without subnet
* @param qstate: query state
* @param id: module id.
* @param sq: subnet qstate
* @return module state
*/
static enum module_ext_state
generate_lookup_without_subnet(struct module_qstate *qstate,
generate_lookup_without_subnet(struct module_qstate *qstate, int id,
struct subnet_qstate* sq)
{
verbose(VERB_ALGO, "subnetcache: make subquery to look up without subnet");
if(!generate_sub_request(qstate, sq)) {
if(!generate_sub_request(qstate, id, sq)) {
verbose(VERB_ALGO, "Could not generate sub query");
qstate->return_rcode = LDNS_RCODE_FORMERR;
qstate->return_rcode = LDNS_RCODE_SERVFAIL;
qstate->return_msg = NULL;
return module_finished;
}
@ -622,7 +651,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
* is still useful to put it in the edns subnet cache for
* when a client explicitly asks for subnet specific answer. */
verbose(VERB_QUERY, "subnetcache: Authority indicates no support");
return generate_lookup_without_subnet(qstate, sq);
return generate_lookup_without_subnet(qstate, id, sq);
}
/* Purposefully there was no sent subnet, and there is consequently
@ -654,7 +683,7 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
qstate->env->cfg->client_subnet_opcode);
sq->subnet_sent = 0;
sq->subnet_sent_no_subnet = 0;
return generate_lookup_without_subnet(qstate, sq);
return generate_lookup_without_subnet(qstate, id, sq);
}
lock_rw_wrlock(&sne->biglock);
@ -945,7 +974,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
/* aggregated this deaggregated state */
qstate->ext_state[id] =
generate_lookup_without_subnet(
qstate, sq);
qstate, id, sq);
return;
}
verbose(VERB_ALGO, "subnetcache: pass to next module");
@ -993,7 +1022,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
qstate->env->cfg->client_subnet_opcode)) {
/* client asked for resolution without edns subnet */
qstate->ext_state[id] = generate_lookup_without_subnet(
qstate, sq);
qstate, id, sq);
return;
}

View file

@ -106,6 +106,10 @@ struct subnet_qstate {
int wait_subquery;
/** The subquery waited for is done. */
int wait_subquery_done;
/** The subnet state is a subquery state for nonsubnet lookup. */
int is_subquery_nonsubnet;
/** This is a subquery, and it is made due to a scope zero request. */
int is_subquery_scopezero;
};
void subnet_data_delete(void* d, void* ATTR_UNUSED(arg));

View file

@ -143,6 +143,8 @@ usage(void)
printf(" load_cache load cache from stdin\n");
printf(" (not supported in remote unbounds in\n");
printf(" multi-process operation)\n");
printf(" cache_lookup [+t] <names> print rrsets and msgs at or under the names\n");
printf(" +t allow tld and root names.\n");
printf(" lookup <name> print nameservers for name\n");
printf(" flush [+c] <name> flushes common types for name from cache\n");
printf(" types: A, AAAA, MX, PTR, NS,\n");

View file

@ -188,6 +188,22 @@ delete_replay_answer(struct replay_answer* a)
free(a);
}
/** Log the packet for a reply_packet from testpkts. */
static void
log_testpkt_reply_pkt(const char* txt, struct reply_packet* reppkt)
{
if(!reppkt) {
log_info("%s <null>", txt);
return;
}
if(reppkt->reply_from_hex) {
log_pkt(txt, sldns_buffer_begin(reppkt->reply_from_hex),
sldns_buffer_limit(reppkt->reply_from_hex));
return;
}
log_pkt(txt, reppkt->reply_pkt, reppkt->reply_len);
}
/**
* return: true if pending query matches the now event.
*/
@ -240,9 +256,8 @@ pending_find_match(struct replay_runtime* runtime, struct entry** entry,
p->start_step, p->end_step, (*entry)->lineno);
if(p->addrlen != 0)
log_addr(0, "matched ip", &p->addr, p->addrlen);
log_pkt("matched pkt: ",
(*entry)->reply_list->reply_pkt,
(*entry)->reply_list->reply_len);
log_testpkt_reply_pkt("matched pkt: ",
(*entry)->reply_list);
return 1;
}
p = p->next_range;
@ -330,7 +345,7 @@ fill_buffer_with_reply(sldns_buffer* buffer, struct entry* entry, uint8_t* q,
while(reppkt && i--)
reppkt = reppkt->next;
if(!reppkt) fatal_exit("extra packet read from TCP stream but none is available");
log_pkt("extra_packet ", reppkt->reply_pkt, reppkt->reply_len);
log_testpkt_reply_pkt("extra packet ", reppkt);
}
if(reppkt->reply_from_hex) {
c = sldns_buffer_begin(reppkt->reply_from_hex);
@ -462,8 +477,7 @@ fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo)
repinfo.c->type = comm_udp;
fill_buffer_with_reply(repinfo.c->buffer, todo->match, NULL, 0, 0);
log_info("testbound: incoming QUERY");
log_pkt("query pkt", todo->match->reply_list->reply_pkt,
todo->match->reply_list->reply_len);
log_testpkt_reply_pkt("query pkt ", todo->match->reply_list);
/* call the callback for incoming queries */
if((*runtime->callback_query)(repinfo.c, runtime->cb_arg,
NETEVENT_NOERROR, &repinfo)) {

View file

@ -45,6 +45,7 @@
#include "util/data/dname.h"
#include "sldns/sbuffer.h"
#include "sldns/str2wire.h"
#include "sldns/wire2str.h"
/** put dname into buffer */
static sldns_buffer*
@ -876,6 +877,262 @@ dname_setup_bufs(sldns_buffer* loopbuf, sldns_buffer* boundbuf)
sldns_buffer_flip(boundbuf);
}
/* Test strings for the test_long_names test. */
/* Each label begins with the length of the label including the length octet. */
char desc_1[] = "Domain is 1 octet too long.";
uint8_t wire_dom_1[] = { /* Bad: Domain: (8x)0031abcdefghijklmnopqrstuvwxyz.0007ab. */
0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e,
0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30,
0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30,
0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33,
0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, /* Bad: */ 0x06, 0x30, 0x30, 0x30, 0x37, 0x61, 0x62, 0x00
};
char desc_2[] = "Domain has the maximum allowed length (255).";
uint8_t wire_dom_2[] = { /* Good: Domain: (8x)0031abcdefghijklmnopqrstuvwxyz.00076a. */
0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e,
0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30,
0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30,
0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33,
0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, /* Good: */ 0x05, 0x30, 0x30, 0x30, 0x36, 0x61, 0x00
};
char desc_3[] = "Domain has a length one label in the 255th position for a total of 257.";
uint8_t wire_dom_3[] = { /* Bad: Domain: (8x(0031abcdefghijklmnopqrstuvwxyz.0006ab.1. */
0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e,
0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30,
0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30,
0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33,
0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, /* Bad: */ 0x05, 0x30, 0x30, 0x30, 0x36, 0x61, 0x01, 0x32, 0x00
};
char desc_4[] = "Domain has the maximum allowed length (255).";
uint8_t wire_dom_4[] = { /* Good: Domain: (8x)0031abcdefghijklmnopqrstuvwxyz.03.03. */
0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e,
0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30,
0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30,
0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33,
0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, /* Good: */ 0x02, 0x30, 0x33, 0x02, 0x30, 0x33, 0x00
};
char desc_5[] = "Domain has a maximum length label (63) in the 255th position.";
uint8_t wire_dom_5[] = { /* Bad: Domain: (8x)0031abcdefghijklmnopqrstuvwxyz.03.03.65abc...zab...zab...ghi. */
0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e,
0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30,
0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30,
0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33,
0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, /* Bad: */ 0x02, 0x30, 0x33, 0x02, 0x30, 0x33, 0x3f, 0x36,
0x33, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x61, 0x62, 0x63, 0x64, 0x65,
0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x00
};
char desc_6[] = "Domain has a too long label (65) in the 255th position.";
uint8_t wire_dom_6[] = { /* Bad: Domain: (8x)0031abcdefghijklmnopqrstuvwxyz.03.03.66abc...zab...zab...ijk. */
0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e,
0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30,
0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30,
0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33,
0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61,
0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, /* Bad: */ 0x02, 0x30, 0x33, 0x02, 0x30, 0x33, 0x41, 0x36,
0x36, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x61, 0x62, 0x63, 0x64, 0x65,
0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x00
};
char desc_7[] = "Domain has a too long label (65) in the 187th position.";
uint8_t wire_dom_7[] = { /* Bad: Domain: (6x)0031abcdefghijklmnopqrstuvwxyz.65abc..zab...zab...ijk. */
0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e,
0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30,
0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30,
0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33,
0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
/* Bad: */ 0x41, 0x36,
0x36, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x61, 0x62, 0x63, 0x64, 0x65,
0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x00
};
char desc_8[] = "Domains has the maximum allowed length and ends with a maximum length label.";
uint8_t wire_dom_8[] = { /* Good: Domain: (6x)0031abcdefghijklmnopqrstuvwxyz.0004.0064abc..zab...zabcdefg. */
0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e,
0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30,
0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30,
0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33,
0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x03, 0x30, 0x30, 0x34 ,/* Good: */ 0x3f, 0x30,
0x30, 0x36, 0x34, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x61, 0x62, 0x63,
0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x00
};
char desc_9[] = "Domains has 254 octets, one less than the maximum allowed length.";
uint8_t wire_dom_9[] = { /* Good: Domain: (6x)0031abcdefghijklmnopqrstuvwxyz.0004.0064abc..zab...zabcdef. */
0x1e, 0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e,
0x30, 0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30,
0x30, 0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30,
0x33, 0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33,
0x31, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x1e, 0x30, 0x30, 0x33, 0x31,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x03, 0x30, 0x30, 0x34 ,/* Good: */ 0x3e, 0x30,
0x30, 0x35, 0x34, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x61, 0x62, 0x63,
0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x00
};
/** Test dname to string with long domain names. */
static void
test_long_names(void)
{
/* Set to 1 for verbose output, 0 turns it off. */
int verbtest = 0;
uint8_t* wire_doms[] = {wire_dom_1, wire_dom_2, wire_dom_3,
wire_dom_4, wire_dom_5, wire_dom_6, wire_dom_7, wire_dom_8,
wire_dom_9, 0};
char* descs[] = {desc_1, desc_2, desc_3, desc_4, desc_5, desc_6,
desc_7, desc_8, desc_9, 0};
int n;
char string_domain[260];
uint8_t** wd = wire_doms;
int di = 0;
int skip = 5; /* 0..6 */
while (*wd) {
if(verbtest)
printf("Test: %s\n", descs[di++]);
memset(string_domain, 0xff, sizeof(string_domain));
dname_str(*wd, string_domain);
for (n = 0 ; n < (int)sizeof(string_domain); ++n) {
if ((uint8_t)string_domain[n] == 0xff)
break;
}
if(verbtest)
printf("dname_str: L=%d, S=Skipping %d labels...%s\n",
n, skip, string_domain + skip*31);
unit_assert(n <= 255);
memset(string_domain, 0xff, sizeof(string_domain));
sldns_wire2str_dname_buf(*wd,
strlen((char*)*wd)+1 /* strlen works with these test strings */,
string_domain,
255 /* for comparable result to dname_str */ );
for (n = 0 ; n < (int)sizeof(string_domain); ++n) {
if ((uint8_t)string_domain[n] == 0xff)
break;
}
if(verbtest)
printf("sldns_wire2str_dname_buf: L=%d, S=Skipping %d labels...%s\n",
n, skip, string_domain + skip*31);
unit_assert(n <= 255);
++wd;
}
}
static void
dname_test_str(sldns_buffer* buff)
{
@ -1019,6 +1276,8 @@ dname_test_str(sldns_buffer* buff)
unit_assert(0);
}
}
test_long_names();
}
void dname_test(void)

View file

@ -0,0 +1,36 @@
server:
verbosity: 7
# num-threads: 1
interface: 127.0.0.1
interface: 127.0.0.1@@PROXYPORT@
port: @PORT@
proxy-protocol-port: @PROXYPORT@
access-control: 1.0.0.0/8 allow
use-syslog: no
directory: ""
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
target-fetch-policy: "0 0 0 0 0"
send-client-subnet: 127.0.0.1
max-client-subnet-ipv4: 17
module-config: "subnetcache iterator"
qname-minimisation: no
minimal-responses: no
remote-control:
control-enable: yes
control-interface: @CONTROL_PATH@/controlpipe.@CONTROL_PID@
control-use-cert: no
stub-zone:
name: "."
stub-prime: no
stub-addr: "127.0.0.1@@TOPORT@"
stub-zone:
name: "example.com"
stub-prime: no
stub-addr: "127.0.0.1@@TOPORT@"
stub-zone:
name: "example.net"
stub-prime: no
stub-addr: "127.0.0.1@@TOPORT@"

View file

@ -0,0 +1,16 @@
BaseName: subnet_cache_lookup
Version: 1.0
Description: Subnet cache contents with unbound-control cache_lookup
CreationDate: Fri Aug 15 11:00:00 CEST 2025
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: subnet_cache_lookup.pre
Post: subnet_cache_lookup.post
Test: subnet_cache_lookup.test
AuxFiles:
Passed:
Failure:

View file

@ -0,0 +1,15 @@
# #-- subnet_cache_lookup.post --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# source the test var file when it's there
[ -f .tpkg.var.test ] && source .tpkg.var.test
#
# do your teardown here
PRE="../.."
. ../common.sh
echo "> cat logfiles"
kill_pid $FWD_PID
kill_pid $UNBOUND_PID
rm -f $CONTROL_PATH/controlpipe.$CONTROL_PID
cat fwd.log
cat unbound.log

View file

@ -0,0 +1,42 @@
# #-- subnet_cache_lookup.pre--#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
if grep "define CLIENT_SUBNET 1" $PRE/config.h; then echo test enabled; else skip_test "test skipped"; fi
get_make
(cd $PRE; $MAKE streamtcp)
get_random_port 3
UNBOUND_PORT=$RND_PORT
PROXY_PORT=$(($RND_PORT + 1))
FWD_PORT=$(($RND_PORT + 2))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "PROXY_PORT=$PROXY_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT subnet_cache_lookup.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
CONTROL_PATH=/tmp
CONTROL_PID=$$
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@PROXYPORT\@/'$PROXY_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' -e 's?@CONTROL_PATH\@?'$CONTROL_PATH'?' -e 's/@CONTROL_PID@/'$CONTROL_PID'/' < subnet_cache_lookup.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
echo "CONTROL_PATH=$CONTROL_PATH" >> .tpkg.var.test
echo "CONTROL_PID=$CONTROL_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log

View file

@ -0,0 +1,121 @@
# #-- subnet_cache_lookup.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
# do the test
echo "> dig www.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 10
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 10
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
#echo "> cat logfiles"
#cat fwd.log
#cat unbound.log
echo "> check answer"
if grep www.example.com outfile | grep "10.20.30.40"; then
echo "OK"
else
echo "Not OK"
exit 1
fi
echo "> unbound-control status"
$PRE/unbound-control -c ub.conf status
if test $? -ne 0; then
echo "wrong exit value."
exit 1
else
echo "exit value: OK"
fi
echo "> unbound-control cache_lookup example.com"
$PRE/unbound-control -c ub.conf cache_lookup example.com 2>&1 | tee outfile
if test $? -ne 0; then
echo "wrong exit value."
exit 1
fi
echo "> check unbound-control output"
if grep "subnet" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
echo "> use proxy-protocol to put more addresses in the edns subnet cache"
$PRE/streamtcp -f 127.0.0.1@$PROXY_PORT -p 1.1.3.4 www.example.net. A IN | tee outfile
if grep www.example.net outfile | grep "10.20.30.41"; then
echo "OK"
else
echo "Not OK"
exit 1
fi
$PRE/streamtcp -f 127.0.0.1@$PROXY_PORT -p 1.2.3.4 www.example.net. A IN | tee outfile
if grep www.example.net outfile | grep "10.20.30.42"; then
echo "OK"
else
echo "Not OK"
exit 1
fi
$PRE/streamtcp -f 127.0.0.1@$PROXY_PORT -p 1.3.3.4 www.example.net. A IN | tee outfile
if grep www.example.net outfile | grep "10.20.30.43"; then
echo "OK"
else
echo "Not OK"
exit 1
fi
$PRE/streamtcp -f 127.0.0.1@$PROXY_PORT -p 1.4.3.4 www.example.net. A IN | tee outfile
if grep www.example.net outfile | grep "10.20.30.44"; then
echo "OK"
else
echo "Not OK"
exit 1
fi
echo "> unbound-control cache_lookup example.net"
$PRE/unbound-control -c ub.conf cache_lookup example.net 2>&1 | tee outfile
if test $? -ne 0; then
echo "wrong exit value."
exit 1
fi
echo "> check unbound-control output"
if grep "subnet" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
exit 0

View file

@ -0,0 +1,181 @@
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS test.ns.
SECTION ADDITIONAL
test.ns. IN A 127.0.0.1
ENTRY_END
; response to query of interest
ENTRY_BEGIN
;MATCH opcode qtype qname ednsdata
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
SECTION AUTHORITY
example.com. IN NS ns.example.com.
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
; client is 127.0.0.1
00 08 ; OPC
00 07 ; option length
00 01 ; Family
11 11 ; source mask, scopemask
7f 00 00 ; address
HEX_EDNSDATA_END
ns.example.com. IN A 1.2.3.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example.com. IN SOA
SECTION ANSWER
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname ednsdata
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
www.example.net. IN A
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
; client is 1.1.3.4
00 08 ; OPC
00 07 ; option length
00 01 ; Family
11 00 ; source mask, scopemask
01 01 00 ; address
HEX_EDNSDATA_END
HEX_ANSWER_BEGIN
00 00 84 00 00 01 00 01 ;ID 0, QR AA
00 00 00 01 03 77 77 77 ; www.example.net. A? (DO)
07 65 78 61 6d 70 6c 65
03 6e 65 74 00 00 01 00
01
; www.example.net. A 10.20.30.41
03 77 77 77 07 65 78 61 6d 70 6c 65 03 6e 65 74 00
00 01 00 01 00 00 0e 10 00 04
0a 14 1e 29
00 00 29 10 00 00 00
80 00 00 0b
00 08 00 07 ; OPC, optlen
00 01 11 11 ; ip4, scope 17, source 17
01 01 00 ;1.1.0.0/17
HEX_ANSWER_END
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname ednsdata
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
www.example.net. IN A
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
; client is 1.2.3.4
00 08 ; OPC
00 07 ; option length
00 01 ; Family
11 00 ; source mask, scopemask
01 02 00 ; address
HEX_EDNSDATA_END
HEX_ANSWER_BEGIN
00 00 84 00 00 01 00 01 ;ID 0, QR AA
00 00 00 01 03 77 77 77 ; www.example.net. A? (DO)
07 65 78 61 6d 70 6c 65
03 6e 65 74 00 00 01 00
01
; www.example.net. A 10.20.30.42
03 77 77 77 07 65 78 61 6d 70 6c 65 03 6e 65 74 00
00 01 00 01 00 00 0e 10 00 04
0a 14 1e 2a
00 00 29 10 00 00 00
80 00 00 0b
00 08 00 07 ; OPC, optlen
00 01 11 11 ; ip4, scope 17, source 17
01 02 00 ;1.2.0.0/17
HEX_ANSWER_END
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname ednsdata
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
www.example.net. IN A
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
; client is 1.3.3.4
00 08 ; OPC
00 07 ; option length
00 01 ; Family
11 00 ; source mask, scopemask
01 03 00 ; address
HEX_EDNSDATA_END
HEX_ANSWER_BEGIN
00 00 84 00 00 01 00 01 ;ID 0, QR AA
00 00 00 01 03 77 77 77 ; www.example.net. A? (DO)
07 65 78 61 6d 70 6c 65
03 6e 65 74 00 00 01 00
01
; www.example.net. A 10.20.30.43
03 77 77 77 07 65 78 61 6d 70 6c 65 03 6e 65 74 00
00 01 00 01 00 00 0e 10 00 04
0a 14 1e 2b
00 00 29 10 00 00 00
80 00 00 0b
00 08 00 07 ; OPC, optlen
00 01 11 11 ; ip4, scope 17, source 17
01 03 00 ;1.3.0.0/17
HEX_ANSWER_END
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname ednsdata
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
www.example.net. IN A
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
; client is 1.4.3.4
00 08 ; OPC
00 07 ; option length
00 01 ; Family
11 00 ; source mask, scopemask
01 04 00 ; address
HEX_EDNSDATA_END
HEX_ANSWER_BEGIN
00 00 84 00 00 01 00 01 ;ID 0, QR AA
00 00 00 01 03 77 77 77 ; www.example.net. A? (DO)
07 65 78 61 6d 70 6c 65
03 6e 65 74 00 00 01 00
01
; www.example.net. A 10.20.30.44
03 77 77 77 07 65 78 61 6d 70 6c 65 03 6e 65 74 00
00 01 00 01 00 00 0e 10 00 04
0a 14 1e 2c
00 00 29 10 00 00 00
80 00 00 0b
00 08 00 07 ; OPC, optlen
00 01 11 11 ; ip4, scope 17, source 17
01 04 00 ;1.4.0.0/17
HEX_ANSWER_END
ENTRY_END

280
testdata/subnet_scopezero_global.crpl vendored Normal file
View file

@ -0,0 +1,280 @@
; config options
server:
target-fetch-policy: "0 0 0 0 0"
module-config: "subnetcache validator iterator"
verbosity: 4
qname-minimisation: no
; the domain is not configured for edns-subnet
;send-client-subnet: 1.2.3.4
client-subnet-zone: "ex2.com"
stub-zone:
name: "."
stub-addr: 193.0.14.129
stub-zone:
name: "example.com"
stub-addr: 1.2.3.4
stub-zone:
name: "ex2.com"
stub-addr: 1.2.3.5
CONFIG_END
SCENARIO_BEGIN Test subnet cache with scope zero for global cache store.
; the upstream server.
RANGE_BEGIN 0 100
ADDRESS 193.0.14.129
ENTRY_BEGIN
MATCH opcode qtype qname ednsdata
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
;; we expect to receive empty
HEX_EDNSDATA_END
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
RANGE_END
RANGE_BEGIN 0 21
ADDRESS 1.2.3.4
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
RANGE_END
RANGE_BEGIN 20 61
ADDRESS 1.2.3.5
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
www.ex2.com. IN A
SECTION ANSWER
www.ex2.com. IN A 10.20.30.41
SECTION AUTHORITY
SECTION ADDITIONAL
ENTRY_END
RANGE_END
RANGE_BEGIN 90 101
ADDRESS 1.2.3.5
ENTRY_BEGIN
MATCH opcode qtype qname ednsdata
ADJUST copy_id copy_ednsdata_assume_clientsubnet
REPLY QR NOERROR
SECTION QUESTION
www.ex2.com. IN A
SECTION ANSWER
www.ex2.com. 10 IN A 10.20.30.42
SECTION AUTHORITY
ex2.com. IN NS ns.ex2.com.
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
; client is 127.0.0.1
00 08 ; OPC
00 07 ; option length
00 01 ; Family
18 00 ; source mask, scopemask
7f 00 00 ; address
HEX_EDNSDATA_END
ns.ex2.com. IN A 1.2.3.5
ENTRY_END
RANGE_END
; query for 0.0.0.0/0
STEP 10 QUERY
ENTRY_BEGIN
HEX_ANSWER_BEGIN
00 00 01 00 00 01 00 00 ;ID 0
00 00 00 01 03 77 77 77 ; www.example.com A? (DO)
07 65 78 61 6d 70 6c 65
03 63 6f 6d 00 00 01 00
01 00 00 29 10 00 00 00
80 00 00 08
00 08 00 04 ; OPC, optlen
00 01 00 00 ; ip4, scope 0, source 0
;0.0.0.0/0
HEX_ANSWER_END
ENTRY_END
STEP 20 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ednsdata
REPLY QR RD RA NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
SECTION AUTHORITY
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
00 08 ; OPC
00 04 ; option length
00 01 ; Family
00 00 ; source mask, scopemask
; address
HEX_EDNSDATA_END
ENTRY_END
; That that it is in global cache.
STEP 30 QUERY
ENTRY_BEGIN
REPLY RD NOERROR
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 40 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ednsdata
REPLY QR RD RA NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. IN A 10.20.30.40
ENTRY_END
; With a query where the name is whitelisted, it should not be stored
; in global cache.
STEP 50 QUERY
ENTRY_BEGIN
HEX_ANSWER_BEGIN
00 00 01 00 00 01 00 00 ;ID 0
00 00 00 01 03 77 77 77 ; www.ex2.com A? (DO)
03 65 78 32 03 63 6f 6d
00 00 01 00 01 00 00 29
10 00 00 00 80 00 00 08
00 08 00 04 ; OPC, optlen
00 01 00 00 ; ip4, scope 0, source 0
;0.0.0.0/0
HEX_ANSWER_END
ENTRY_END
STEP 60 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ednsdata
REPLY QR RD RA NOERROR
SECTION QUESTION
www.ex2.com. IN A
SECTION ANSWER
www.ex2.com. IN A 10.20.30.41
SECTION AUTHORITY
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
00 08 ; OPC
00 04 ; option length
00 01 ; Family
00 00 ; source mask, scopemask
; address
HEX_EDNSDATA_END
ENTRY_END
STEP 70 QUERY
ENTRY_BEGIN
HEX_ANSWER_BEGIN
00 00 01 00 00 01 00 00 ;ID 0
00 00 00 01 03 77 77 77 ; www.ex2.com A? (DO)
03 65 78 32 03 63 6f 6d
00 00 01 00 01 00 00 29
10 00 00 00 80 00 00 08
00 08 00 04 ; OPC, optlen
00 01 00 00 ; ip4, scope 0, source 0
;0.0.0.0/0
HEX_ANSWER_END
ENTRY_END
STEP 80 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ednsdata
REPLY QR RD RA NOERROR
SECTION QUESTION
www.ex2.com. IN A
SECTION ANSWER
www.ex2.com. IN A 10.20.30.41
SECTION AUTHORITY
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
00 08 ; OPC
00 04 ; option length
00 01 ; Family
00 00 ; source mask, scopemask
; address
HEX_EDNSDATA_END
ENTRY_END
; www.ex2.com is not in the global cache. and gets subnet treatment
STEP 90 QUERY
ENTRY_BEGIN
REPLY RD NOERROR
SECTION QUESTION
www.ex2.com. IN A
ENTRY_END
STEP 100 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ednsdata
REPLY QR RD RA NOERROR
SECTION QUESTION
www.ex2.com. IN A
SECTION ANSWER
www.ex2.com. IN A 10.20.30.42
ENTRY_END
; that result is in the subnet cache
STEP 110 QUERY
ENTRY_BEGIN
HEX_ANSWER_BEGIN
00 00 01 00 00 01 00 00 ;ID 0
00 00 00 01 03 77 77 77 ; www.ex2.com A? (DO)
03 65 78 32 03 63 6f 6d
00 00 01 00 01 00 00 29
10 00 00 00 80 00 00 0b
00 08 00 07 ; OPC, optlen
; ip4 127.0.0.0/24 scope /0
00 01 ; Family
18 00 ; source mask, scopemask
7f 00 00 ; address
HEX_ANSWER_END
ENTRY_END
STEP 120 CHECK_ANSWER
ENTRY_BEGIN
MATCH all ednsdata
REPLY QR RD RA NOERROR
SECTION QUESTION
www.ex2.com. IN A
SECTION ANSWER
www.ex2.com. IN A 10.20.30.42
SECTION AUTHORITY
SECTION ADDITIONAL
HEX_EDNSDATA_BEGIN
00 08 ; OPC
00 07 ; option length
; ip4 127.0.0.0/24 scope /24
00 01 ; Family
18 18 ; source mask, scopemask
7f 00 00 ; address
HEX_EDNSDATA_END
ENTRY_END
SCENARIO_END

View file

@ -644,20 +644,22 @@ void dname_str(uint8_t* dname, char* str)
if(!dname || !*dname) {
*s++ = '.';
*s = 0;
goto out;
return;
}
lablen = *dname++;
while(lablen) {
len += lablen+1;
if(len >= LDNS_MAX_DOMAINLEN) {
if ((s-str) >= (LDNS_MAX_DOMAINLEN-1))
s = str + LDNS_MAX_DOMAINLEN - 2;
*s++ = '&';
*s = 0;
return;
}
if(lablen > LDNS_MAX_LABELLEN) {
*s++ = '#';
*s = 0;
goto out;
}
len += lablen+1;
if(len >= LDNS_MAX_DOMAINLEN) {
*s++ = '&';
*s = 0;
goto out;
return;
}
while(lablen--) {
if(isalnum((unsigned char)*dname)
@ -673,10 +675,6 @@ void dname_str(uint8_t* dname, char* str)
lablen = *dname++;
}
*s = 0;
out:
log_assert(s - str < LDNS_MAX_DOMAINLEN);
return;
}
int

View file

@ -3218,6 +3218,9 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
}
/* accept incoming connection. */
c_hdl = c->tcp_free;
/* Should not happen: inconsistent tcp_free state in
* accept_callback. */
log_assert(c_hdl->is_in_tcp_free);
/* clear leftover flags from previous use, and then set the
* correct event base for the event structure for libevent */
ub_event_free(c_hdl->ev->ev);
@ -3292,10 +3295,15 @@ comm_point_tcp_accept_callback(int fd, short event, void* arg)
#endif
}
/* Paranoia: Check that the state has not changed from above: */
/* Should not happen: tcp_free state changed within accept_callback. */
log_assert(c_hdl == c->tcp_free);
log_assert(c_hdl->is_in_tcp_free);
/* grab the tcp handler buffers */
c->cur_tcp_count++;
c->tcp_free = c_hdl->tcp_free;
c_hdl->tcp_free = NULL;
c_hdl->is_in_tcp_free = 0;
if(!c->tcp_free) {
/* stop accepting incoming queries for now. */
comm_point_stop_listening(c);
@ -3316,12 +3324,14 @@ reclaim_tcp_handler(struct comm_point* c)
#endif
}
comm_point_close(c);
if(c->tcp_parent) {
if(c != c->tcp_parent->tcp_free) {
c->tcp_parent->cur_tcp_count--;
c->tcp_free = c->tcp_parent->tcp_free;
c->tcp_parent->tcp_free = c;
}
if(c->tcp_parent && !c->is_in_tcp_free) {
/* Should not happen: bad tcp_free state in reclaim_tcp. */
log_assert(c->tcp_free == NULL);
log_assert(c->tcp_parent->cur_tcp_count > 0);
c->tcp_parent->cur_tcp_count--;
c->tcp_free = c->tcp_parent->tcp_free;
c->tcp_parent->tcp_free = c;
c->is_in_tcp_free = 1;
if(!c->tcp_free) {
/* re-enable listening on accept socket */
comm_point_start_listening(c->tcp_parent, -1, -1);
@ -4707,12 +4717,14 @@ reclaim_http_handler(struct comm_point* c)
#endif
}
comm_point_close(c);
if(c->tcp_parent) {
if(c != c->tcp_parent->tcp_free) {
c->tcp_parent->cur_tcp_count--;
c->tcp_free = c->tcp_parent->tcp_free;
c->tcp_parent->tcp_free = c;
}
if(c->tcp_parent && !c->is_in_tcp_free) {
/* Should not happen: bad tcp_free state in reclaim_http. */
log_assert(c->tcp_free == NULL);
log_assert(c->tcp_parent->cur_tcp_count > 0);
c->tcp_parent->cur_tcp_count--;
c->tcp_free = c->tcp_parent->tcp_free;
c->tcp_parent->tcp_free = c;
c->is_in_tcp_free = 1;
if(!c->tcp_free) {
/* re-enable listening on accept socket */
comm_point_start_listening(c->tcp_parent, -1, -1);
@ -5748,6 +5760,7 @@ comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
c->cur_tcp_count = 0;
c->tcp_handlers = NULL;
c->tcp_free = NULL;
c->is_in_tcp_free = 0;
c->type = comm_udp;
c->tcp_do_close = 0;
c->do_not_close = 0;
@ -5812,6 +5825,7 @@ comm_point_create_udp_ancil(struct comm_base *base, int fd,
c->cur_tcp_count = 0;
c->tcp_handlers = NULL;
c->tcp_free = NULL;
c->is_in_tcp_free = 0;
c->type = comm_udp;
c->tcp_do_close = 0;
c->do_not_close = 0;
@ -5879,6 +5893,7 @@ comm_point_create_doq(struct comm_base *base, int fd, sldns_buffer* buffer,
c->cur_tcp_count = 0;
c->tcp_handlers = NULL;
c->tcp_free = NULL;
c->is_in_tcp_free = 0;
c->type = comm_doq;
c->tcp_do_close = 0;
c->do_not_close = 0;
@ -5979,6 +5994,7 @@ comm_point_create_tcp_handler(struct comm_base *base,
c->cur_tcp_count = 0;
c->tcp_handlers = NULL;
c->tcp_free = NULL;
c->is_in_tcp_free = 0;
c->type = comm_tcp;
c->tcp_do_close = 0;
c->do_not_close = 0;
@ -6016,6 +6032,7 @@ comm_point_create_tcp_handler(struct comm_base *base,
/* add to parent free list */
c->tcp_free = parent->tcp_free;
parent->tcp_free = c;
c->is_in_tcp_free = 1;
/* ub_event stuff */
evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT;
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
@ -6078,6 +6095,7 @@ comm_point_create_http_handler(struct comm_base *base,
c->cur_tcp_count = 0;
c->tcp_handlers = NULL;
c->tcp_free = NULL;
c->is_in_tcp_free = 0;
c->type = comm_http;
c->tcp_do_close = 1;
c->do_not_close = 0;
@ -6136,6 +6154,7 @@ comm_point_create_http_handler(struct comm_base *base,
/* add to parent free list */
c->tcp_free = parent->tcp_free;
parent->tcp_free = c;
c->is_in_tcp_free = 1;
/* ub_event stuff */
evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT;
c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits,
@ -6197,6 +6216,7 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num,
return NULL;
}
c->tcp_free = NULL;
c->is_in_tcp_free = 0;
c->type = comm_tcp_accept;
c->tcp_do_close = 0;
c->do_not_close = 0;
@ -6291,6 +6311,7 @@ comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
c->cur_tcp_count = 0;
c->tcp_handlers = NULL;
c->tcp_free = NULL;
c->is_in_tcp_free = 0;
c->type = comm_tcp;
c->tcp_do_close = 0;
c->do_not_close = 0;
@ -6355,6 +6376,7 @@ comm_point_create_http_out(struct comm_base *base, size_t bufsize,
c->cur_tcp_count = 0;
c->tcp_handlers = NULL;
c->tcp_free = NULL;
c->is_in_tcp_free = 0;
c->type = comm_http;
c->tcp_do_close = 0;
c->do_not_close = 0;
@ -6425,6 +6447,7 @@ comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
c->cur_tcp_count = 0;
c->tcp_handlers = NULL;
c->tcp_free = NULL;
c->is_in_tcp_free = 0;
c->type = comm_local;
c->tcp_do_close = 0;
c->do_not_close = 1;
@ -6488,6 +6511,7 @@ comm_point_create_raw(struct comm_base* base, int fd, int writing,
c->cur_tcp_count = 0;
c->tcp_handlers = NULL;
c->tcp_free = NULL;
c->is_in_tcp_free = 0;
c->type = comm_raw;
c->tcp_do_close = 0;
c->do_not_close = 1;

View file

@ -238,6 +238,8 @@ struct comm_point {
/** linked list of free tcp_handlers to use for new queries.
For tcp_accept the first entry, for tcp_handlers the next one. */
struct comm_point* tcp_free;
/** Whether this struct is in its parent's tcp_free list */
int is_in_tcp_free;
/* -------- SSL TCP DNS ------- */
/** the SSL object with rw bio (owned) or for commaccept ctx ref */