diff --git a/daemon/worker.c b/daemon/worker.c index 44a989a..3acecc1 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1193,7 +1193,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error, if(worker->env.cfg->log_queries) { char ip[128]; addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); - log_nametypeclass(0, ip, qinfo.qname, qinfo.qtype, qinfo.qclass); + log_query_in(ip, qinfo.qname, qinfo.qtype, qinfo.qclass); } if(qinfo.qtype == LDNS_RR_TYPE_AXFR || qinfo.qtype == LDNS_RR_TYPE_IXFR) { diff --git a/doc/Changelog b/doc/Changelog index 3d05ae5..bb74461 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,15 @@ +30 November 2018: Wouter + - log-tag-queryreply: yes in unbound.conf tags the log-queries and + log-replies in the log file for easier log filter maintenance. + +21 August 2018: Wouter + - log-local-actions: yes option for unbound.conf that logs all the + local zone actions, a patch from Saksham Manchanda (Secure64). + +17 August 2018: Wouter + - log-servfail: yes prints log lines that say why queries are + returning SERVFAIL to clients. + 19 June 2018: Wouter - Fix for unbound-control on Windows and set TCP socket parameters more closely. diff --git a/doc/example.conf.in b/doc/example.conf.in index be83bda..aa06cee 100644 --- a/doc/example.conf.in +++ b/doc/example.conf.in @@ -309,6 +309,17 @@ server: # timetoresolve, fromcache and responsesize. # log-replies: no + # log with tag 'query' and 'reply' instead of 'info' for + # filtering log-queries and log-replies from the log. + # log-tag-queryreply: no + + # log the local-zone actions, like local-zone type inform is enabled + # also for the other local zone types. + # log-local-actions: no + + # print log lines that say why queries return SERVFAIL to clients. + # log-servfail: no + # the pid file. Can be an absolute path outside of chroot/work dir. # pidfile: "@UNBOUND_PIDFILE@" diff --git a/doc/unbound.conf.5.in b/doc/unbound.conf.5.in index 9167a5a..b73bc70 100644 --- a/doc/unbound.conf.5.in +++ b/doc/unbound.conf.5.in @@ -618,6 +618,21 @@ Default is no. Note that it takes time to print these lines which makes the server (significantly) slower. Odd (nonprintable) characters in names are printed as '?'. .TP +.B log\-tag\-queryreply: \fI +Prints the word 'query' and 'reply' with log\-queries and log\-replies. +This makes filtering logs easier. The default is off (for backwards +compatibility). +.TP +.B log\-local\-actions: \fI +Print log lines to inform about local zone actions. These lines are like the +local\-zone type inform prints out, but they are also printed for the other +types of local zones. +.TP +.B log\-servfail: \fI +Print log lines that say why queries return SERVFAIL to clients. +This is separate from the verbosity debug logs, much smaller, and printed +at the error level, not the info level of debug info from verbosity. +.TP .B pidfile: \fI The process id is written to the file. Default is "@UNBOUND_PIDFILE@". So, diff --git a/services/localzone.c b/services/localzone.c index 0f60817..a85619b 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -1459,7 +1459,7 @@ lz_inform_print(struct local_zone* z, struct query_info* qinfo, uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port); dname_str(z->name, zname); addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip)); - snprintf(txt, sizeof(txt), "%s inform %s@%u", zname, ip, + snprintf(txt, sizeof(txt), "%s %s %s@%u", zname, local_zone_type2str(z->type), ip, (unsigned)port); log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass); } @@ -1576,7 +1576,8 @@ local_zones_answer(struct local_zones* zones, struct module_env* env, z->override_tree, &tag, tagname, num_tags); lock_rw_unlock(&zones->lock); } - if((lzt == local_zone_inform || lzt == local_zone_inform_deny) + if((env->cfg->log_local_actions || + lzt == local_zone_inform || lzt == local_zone_inform_deny) && repinfo) lz_inform_print(z, qinfo, repinfo); diff --git a/services/mesh.c b/services/mesh.c index 41aba74..55c1947 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -977,7 +977,7 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, rcode = LDNS_RCODE_SERVFAIL; if(!rcode && (rep->security == sec_status_bogus || rep->security == sec_status_secure_sentinel_fail)) { - if(!(reason = errinf_to_str(&m->s))) + if(!(reason = errinf_to_str_bogus(&m->s))) rcode = LDNS_RCODE_SERVFAIL; } /* send the reply */ @@ -1148,6 +1148,15 @@ void mesh_query_done(struct mesh_state* mstate) struct mesh_cb* c; struct reply_info* rep = (mstate->s.return_msg? mstate->s.return_msg->rep:NULL); + if((mstate->s.return_rcode == LDNS_RCODE_SERVFAIL || + (rep && FLAGS_GET_RCODE(rep->flags) == LDNS_RCODE_SERVFAIL)) + && mstate->s.env->cfg->log_servfail + && !mstate->s.env->cfg->val_log_squelch) { + char* err = errinf_to_str_servfail(&mstate->s); + if(err) + log_err("%s", err); + free(err); + } for(r = mstate->reply_list; r; r = r->next) { /* if a response-ip address block has been stored the * information should be logged for each client. */ diff --git a/util/config_file.c b/util/config_file.c index b061760..68a0a15 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -115,6 +115,9 @@ config_create(void) cfg->log_time_ascii = 0; cfg->log_queries = 0; cfg->log_replies = 0; + cfg->log_tag_queryreply = 0; + cfg->log_local_actions = 0; + cfg->log_servfail = 0; #ifndef USE_WINSOCK # ifdef USE_MINI_EVENT /* select max 1024 sockets */ @@ -540,6 +543,9 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_YNO("val-log-squelch:", val_log_squelch) else S_YNO("log-queries:", log_queries) else S_YNO("log-replies:", log_replies) + else S_YNO("log-tag-queryreply:", log_tag_queryreply) + else S_YNO("log-local-actions:", log_local_actions) + else S_YNO("log-servfail:", log_servfail) else S_YNO("val-permissive-mode:", val_permissive_mode) else S_YNO("aggressive-nsec:", aggressive_nsec) else S_YNO("ignore-cd-flag:", ignore_cd) @@ -893,6 +899,9 @@ config_get_option(struct config_file* cfg, const char* opt, else O_STR(opt, "logfile", logfile) else O_YNO(opt, "log-queries", log_queries) else O_YNO(opt, "log-replies", log_replies) + else O_YNO(opt, "log-tag-queryreply", log_tag_queryreply) + else O_YNO(opt, "log-local-actions", log_local_actions) + else O_YNO(opt, "log-servfail", log_servfail) else O_STR(opt, "pidfile", pidfile) else O_YNO(opt, "hide-identity", hide_identity) else O_YNO(opt, "hide-version", hide_version) @@ -1845,6 +1854,7 @@ config_apply(struct config_file* config) EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size; MINIMAL_RESPONSES = config->minimal_responses; RRSET_ROUNDROBIN = config->rrset_roundrobin; + LOG_TAG_QUERYREPLY = config->log_tag_queryreply; log_set_time_asc(config->log_time_ascii); autr_permit_small_holddown = config->permit_small_holddown; } @@ -2220,7 +2230,7 @@ void errinf_origin(struct module_qstate* qstate, struct sock_list *origin) } } -char* errinf_to_str(struct module_qstate* qstate) +char* errinf_to_str_bogus(struct module_qstate* qstate) { char buf[20480]; char* p = buf; @@ -2245,6 +2255,31 @@ char* errinf_to_str(struct module_qstate* qstate) return p; } +char* errinf_to_str_servfail(struct module_qstate* qstate) +{ + char buf[20480]; + char* p = buf; + size_t left = sizeof(buf); + struct config_strlist* s; + char dname[LDNS_MAX_DOMAINLEN+1]; + char t[16], c[16]; + sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t)); + sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c)); + dname_str(qstate->qinfo.qname, dname); + snprintf(p, left, "SERVFAIL <%s %s %s>:", dname, t, c); + left -= strlen(p); p += strlen(p); + if(!qstate->errinf) + snprintf(p, left, " misc failure"); + else for(s=qstate->errinf; s; s=s->next) { + snprintf(p, left, " %s", s->str); + left -= strlen(p); p += strlen(p); + } + p = strdup(buf); + if(!p) + log_err("malloc failure in errinf_to_str"); + return p; +} + void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr) { char buf[1024]; diff --git a/util/config_file.h b/util/config_file.h index 4206eb9..1e7f402 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -268,6 +268,12 @@ struct config_file { int log_queries; /** log replies with one line per reply */ int log_replies; + /** tag log_queries and log_replies for filtering */ + int log_tag_queryreply; + /** log every local-zone hit **/ + int log_local_actions; + /** log servfails with a reason */ + int log_servfail; /** log identity to report */ char* log_identity; @@ -1070,7 +1076,15 @@ void errinf_dname(struct module_qstate* qstate, const char* str, * @return string or NULL on malloc failure (already logged). * This string is malloced and has to be freed by caller. */ -char* errinf_to_str(struct module_qstate* qstate); +char* errinf_to_str_bogus(struct module_qstate* qstate); + +/** + * Create error info in string. For other servfails. + * @param qstate: query state. + * @return string or NULL on malloc failure (already logged). + * This string is malloced and has to be freed by caller. + */ +char* errinf_to_str_servfail(struct module_qstate* qstate); /** * Used during options parsing diff --git a/util/configlexer.lex b/util/configlexer.lex index 6124e32..9b22db1 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -366,6 +366,9 @@ log-identity{COLON} { YDVAR(1, VAR_LOG_IDENTITY) } log-time-ascii{COLON} { YDVAR(1, VAR_LOG_TIME_ASCII) } log-queries{COLON} { YDVAR(1, VAR_LOG_QUERIES) } log-replies{COLON} { YDVAR(1, VAR_LOG_REPLIES) } +log-tag-queryreply{COLON} { YDVAR(1, VAR_LOG_TAG_QUERYREPLY) } +log-local-actions{COLON} { YDVAR(1, VAR_LOG_LOCAL_ACTIONS) } +log-servfail{COLON} { YDVAR(1, VAR_LOG_SERVFAIL) } local-zone{COLON} { YDVAR(2, VAR_LOCAL_ZONE) } local-data{COLON} { YDVAR(1, VAR_LOCAL_DATA) } local-data-ptr{COLON} { YDVAR(1, VAR_LOCAL_DATA_PTR) } diff --git a/util/configparser.y b/util/configparser.y index e34665a..4b23a71 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -106,7 +106,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_AUTO_TRUST_ANCHOR_FILE VAR_KEEP_MISSING VAR_ADD_HOLDDOWN %token VAR_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE VAR_PREFETCH %token VAR_PREFETCH_KEY VAR_SO_SNDBUF VAR_SO_REUSEPORT VAR_HARDEN_BELOW_NXDOMAIN -%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_LOG_REPLIES +%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_LOG_REPLIES VAR_LOG_LOCAL_ACTIONS %token VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM %token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST %token VAR_STUB_SSL_UPSTREAM VAR_FORWARD_SSL_UPSTREAM VAR_TLS_CERT_BUNDLE @@ -158,6 +158,8 @@ extern struct config_parser_state* cfg_parser; %token VAR_AUTH_ZONE VAR_ZONEFILE VAR_MASTER VAR_URL VAR_FOR_DOWNSTREAM %token VAR_FALLBACK_ENABLED VAR_TLS_ADDITIONAL_PORT VAR_LOW_RTT VAR_LOW_RTT_PERMIL %token VAR_ALLOW_NOTIFY VAR_TLS_WIN_CERT +%token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL +%token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -217,6 +219,7 @@ content_server: server_num_threads | server_verbosity | server_port | server_edns_buffer_size | server_prefetch | server_prefetch_key | server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag | server_log_queries | server_log_replies | server_tcp_upstream | server_ssl_upstream | + server_log_local_actions | server_ssl_service_key | server_ssl_service_pem | server_ssl_port | server_minimal_responses | server_rrset_roundrobin | server_max_udp_size | server_so_reuseport | server_delay_close | @@ -249,7 +252,9 @@ content_server: server_num_threads | server_verbosity | server_port | server_ipsecmod_whitelist | server_ipsecmod_strict | server_udp_upstream_without_downstream | server_aggressive_nsec | server_tls_cert_bundle | server_tls_additional_port | server_low_rtt | - server_low_rtt_permil | server_tls_win_cert + server_low_rtt_permil | server_tls_win_cert | + server_tcp_connection_limit | server_log_servfail | + server_unknown_server_time_limit | server_log_tag_queryreply ; stubstart: VAR_STUB_ZONE { @@ -764,6 +769,33 @@ server_log_replies: VAR_LOG_REPLIES STRING_ARG free($2); } ; +server_log_tag_queryreply: VAR_LOG_TAG_QUERYREPLY STRING_ARG + { + OUTYY(("P(server_log_tag_queryreply:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->log_tag_queryreply = (strcmp($2, "yes")==0); + free($2); + } + ; +server_log_servfail: VAR_LOG_SERVFAIL STRING_ARG + { + OUTYY(("P(server_log_servfail:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->log_servfail = (strcmp($2, "yes")==0); + free($2); + } + ; +server_log_local_actions: VAR_LOG_LOCAL_ACTIONS STRING_ARG + { + OUTYY(("P(server_log_local_actions:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->log_local_actions = (strcmp($2, "yes")==0); + free($2); + } + ; server_chroot: VAR_CHROOT STRING_ARG { OUTYY(("P(server_chroot:%s)\n", $2)); diff --git a/util/data/msgreply.c b/util/data/msgreply.c index 772f5d1..df2131c 100644 --- a/util/data/msgreply.c +++ b/util/data/msgreply.c @@ -844,7 +844,9 @@ log_reply_info(enum verbosity_value v, struct query_info *qinf, addr_to_str(addr, addrlen, clientip_buf, sizeof(clientip_buf)); if(rcode == LDNS_RCODE_FORMERR) { - log_info("%s - - - %s - - - ", clientip_buf, rcode_buf); + if(LOG_TAG_QUERYREPLY) + log_reply("%s - - - %s - - - ", clientip_buf, rcode_buf); + else log_info("%s - - - %s - - - ", clientip_buf, rcode_buf); } else { if(qinf->qname) dname_str(qinf->qname, qname_buf); @@ -852,7 +854,11 @@ log_reply_info(enum verbosity_value v, struct query_info *qinf, pktlen = sldns_buffer_limit(rmsg); sldns_wire2str_type_buf(qinf->qtype, type_buf, sizeof(type_buf)); sldns_wire2str_class_buf(qinf->qclass, class_buf, sizeof(class_buf)); - log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d", + if(LOG_TAG_QUERYREPLY) + log_reply("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d", + clientip_buf, qname_buf, type_buf, class_buf, + rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen); + else log_info("%s %s %s %s %s " ARG_LL "d.%6.6d %d %d", clientip_buf, qname_buf, type_buf, class_buf, rcode_buf, (long long)dur.tv_sec, (int)dur.tv_usec, cached, (int)pktlen); } diff --git a/util/log.c b/util/log.c index 43dd572..fff4319 100644 --- a/util/log.c +++ b/util/log.c @@ -391,6 +391,24 @@ log_hex(const char* msg, void* data, size_t length) log_hex_f(verbosity, msg, data, length); } +void +log_query(const char *format, ...) +{ + va_list args; + va_start(args, format); + log_vmsg(LOG_INFO, "query", format, args); + va_end(args); +} + +void +log_reply(const char *format, ...) +{ + va_list args; + va_start(args, format); + log_vmsg(LOG_INFO, "reply", format, args); + va_end(args); +} + void log_buf(enum verbosity_value level, const char* msg, sldns_buffer* buf) { if(verbosity < level) diff --git a/util/log.h b/util/log.h index 7bc3d9e..172cd01 100644 --- a/util/log.h +++ b/util/log.h @@ -160,6 +160,20 @@ void log_warn(const char* format, ...) ATTR_FORMAT(printf, 1, 2); */ void log_hex(const char* msg, void* data, size_t length); +/** + * Log query. + * Pass printf formatted arguments. No trailing newline is needed. + * @param format: printf-style format string. Arguments follow. + */ +void log_query(const char* format, ...) ATTR_FORMAT(printf, 1, 2); + +/** + * Log reply. + * Pass printf formatted arguments. No trailing newline is needed. + * @param format: printf-style format string. Arguments follow. + */ +void log_reply(const char* format, ...) ATTR_FORMAT(printf, 1, 2); + /** * Easy alternative for log_hex, takes a sldns_buffer. * @param level: verbosity level for this message, compared to global diff --git a/util/net_help.c b/util/net_help.c index a193c36..617a896 100644 --- a/util/net_help.c +++ b/util/net_help.c @@ -67,6 +67,9 @@ int MINIMAL_RESPONSES = 0; /** rrset order roundrobin: default is no */ int RRSET_ROUNDROBIN = 0; +/** log tag queries with name instead of 'info' for filtering */ +int LOG_TAG_QUERYREPLY = 0; + /* returns true is string addr is an ip6 specced address */ int str_is_ip6(const char* str) @@ -335,7 +338,7 @@ log_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name, { char buf[LDNS_MAX_DOMAINLEN+1]; char t[12], c[12]; - const char *ts, *cs; + const char *ts, *cs; if(verbosity < v) return; dname_str(name, buf); @@ -361,6 +364,37 @@ log_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name, log_info("%s %s %s %s", str, buf, ts, cs); } +void +log_query_in(const char* str, uint8_t* name, uint16_t type, uint16_t dclass) +{ + char buf[LDNS_MAX_DOMAINLEN+1]; + char t[12], c[12]; + const char *ts, *cs; + dname_str(name, buf); + if(type == LDNS_RR_TYPE_TSIG) ts = "TSIG"; + else if(type == LDNS_RR_TYPE_IXFR) ts = "IXFR"; + else if(type == LDNS_RR_TYPE_AXFR) ts = "AXFR"; + else if(type == LDNS_RR_TYPE_MAILB) ts = "MAILB"; + else if(type == LDNS_RR_TYPE_MAILA) ts = "MAILA"; + else if(type == LDNS_RR_TYPE_ANY) ts = "ANY"; + else if(sldns_rr_descript(type) && sldns_rr_descript(type)->_name) + ts = sldns_rr_descript(type)->_name; + else { + snprintf(t, sizeof(t), "TYPE%d", (int)type); + ts = t; + } + if(sldns_lookup_by_id(sldns_rr_classes, (int)dclass) && + sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name) + cs = sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name; + else { + snprintf(c, sizeof(c), "CLASS%d", (int)dclass); + cs = c; + } + if(LOG_TAG_QUERYREPLY) + log_query("%s %s %s %s", str, buf, ts, cs); + else log_info("%s %s %s %s", str, buf, ts, cs); +} + void log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone, struct sockaddr_storage* addr, socklen_t addrlen) { diff --git a/util/net_help.h b/util/net_help.h index de2e1ac..f2e0e43 100644 --- a/util/net_help.h +++ b/util/net_help.h @@ -99,6 +99,9 @@ extern int MINIMAL_RESPONSES; /** rrset order roundrobin */ extern int RRSET_ROUNDROBIN; +/** log tag queries with name instead of 'info' for filtering */ +extern int LOG_TAG_QUERYREPLY; + /** * See if string is ip4 or ip6. * @param str: IP specification. @@ -235,6 +238,12 @@ void sockaddr_store_port(struct sockaddr_storage* addr, socklen_t addrlen, void log_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name, uint16_t type, uint16_t dclass); +/** + * Like log_nametypeclass, but logs with log_query for query logging + */ +void log_query_in(const char* str, uint8_t* name, uint16_t type, + uint16_t dclass); + /** * Compare two sockaddrs. Imposes an ordering on the addresses. * Compares address and port. diff --git a/validator/val_kcache.c b/validator/val_kcache.c index 22070cc..e0b88b6 100644 --- a/validator/val_kcache.c +++ b/validator/val_kcache.c @@ -89,7 +89,7 @@ key_cache_insert(struct key_cache* kcache, struct key_entry_key* kkey, if(key_entry_isbad(k) && qstate->errinf && qstate->env->cfg->val_log_level >= 2) { /* on malloc failure there is simply no reason string */ - key_entry_set_reason(k, errinf_to_str(qstate)); + key_entry_set_reason(k, errinf_to_str_bogus(qstate)); } key_entry_hash(k); slabhash_insert(kcache->slab, k->entry.hash, &k->entry, diff --git a/validator/validator.c b/validator/validator.c index 5777b29..2d9cc17 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -2227,13 +2227,15 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq, vq->orig_msg->rep->ttl = ve->bogus_ttl; vq->orig_msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(vq->orig_msg->rep->ttl); - if(qstate->env->cfg->val_log_level >= 1 && + if((qstate->env->cfg->val_log_level >= 1 || + qstate->env->cfg->log_servfail) && !qstate->env->cfg->val_log_squelch) { - if(qstate->env->cfg->val_log_level < 2) + if(qstate->env->cfg->val_log_level < 2 && + !qstate->env->cfg->log_servfail) log_query_info(0, "validation failure", &qstate->qinfo); else { - char* err = errinf_to_str(qstate); + char* err = errinf_to_str_bogus(qstate); if(err) log_info("%s", err); free(err); } @@ -2332,6 +2334,7 @@ processDLVLookup(struct module_qstate* qstate, struct val_qstate* vq, if(vq->dlv_status == dlv_error) { verbose(VERB_QUERY, "failed DLV lookup"); + errinf(qstate, "failed DLV lookup"); return val_error(qstate, id); } else if(vq->dlv_status == dlv_success) { uint8_t* nm;