#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>
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));
+ 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)))
+ return;
+ 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,
+ "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)
+ return;
+ addrlen = edge->len;
+ /* ceil() */
+ n = (size_t)((addrlen / KEYWIDTH) + ((addrlen % KEYWIDTH != 0)?1:0));
+ if(n > addr_size)
+ n = 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)
{
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);
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) {
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);