Blame SOURCES/unbound-1.7.3-additional-logging.patch

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