From ff8013787647d7cababee01735f7ebda93e145a3 Mon Sep 17 00:00:00 2001
From: CentOS Sources <bugs@centos.org>
Date: May 18 2021 06:43:07 +0000
Subject: import unbound-1.7.3-15.el8


---

diff --git a/SOURCES/unbound-1.7.3-additional-logging.patch b/SOURCES/unbound-1.7.3-additional-logging.patch
new file mode 100644
index 0000000..7630422
--- /dev/null
+++ b/SOURCES/unbound-1.7.3-additional-logging.patch
@@ -0,0 +1,553 @@
+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<yes or no>
++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<yes or no>
++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<yes or no>
++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<filename>
+ 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;
diff --git a/SOURCES/unbound-1.7.3-crypto-policy-non-compliance-openssl.patch b/SOURCES/unbound-1.7.3-crypto-policy-non-compliance-openssl.patch
new file mode 100644
index 0000000..6d4b906
--- /dev/null
+++ b/SOURCES/unbound-1.7.3-crypto-policy-non-compliance-openssl.patch
@@ -0,0 +1,13 @@
+diff --git a/util/net_help.c b/util/net_help.c
+index a5059b0..a193c36 100644
+--- a/util/net_help.c
++++ b/util/net_help.c
+@@ -703,7 +703,7 @@ listen_sslctx_setup(void* ctxt)
+ #endif
+ #if defined(SHA256_DIGEST_LENGTH) && defined(USE_ECDSA)
+ 	/* if we have sha256, set the cipher list to have no known vulns */
+-	if(!SSL_CTX_set_cipher_list(ctx, "TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"))
++	if(!SSL_CTX_set_cipher_list(ctx, "PROFILE=SYSTEM"))
+ 		log_crypto_err("could not set cipher list with SSL_CTX_set_cipher_list");
+ #endif
+ 
diff --git a/SOURCES/unbound-1.7.3-security-hardening.patch b/SOURCES/unbound-1.7.3-security-hardening.patch
new file mode 100644
index 0000000..930bbad
--- /dev/null
+++ b/SOURCES/unbound-1.7.3-security-hardening.patch
@@ -0,0 +1,677 @@
+diff --git a/config.h.in b/config.h.in
+index 04356f3..3b06bfa 100644
+--- a/config.h.in
++++ b/config.h.in
+@@ -666,6 +666,9 @@
+ /* Shared data */
+ #undef SHARE_DIR
+ 
++/* The size of `size_t', as computed by sizeof. */
++#undef SIZEOF_SIZE_T
++
+ /* The size of `time_t', as computed by sizeof. */
+ #undef SIZEOF_TIME_T
+ 
+diff --git a/configure.ac b/configure.ac
+index c5e0c7b..1bff4ed 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -371,6 +371,7 @@ AC_INCLUDES_DEFAULT
+ # endif
+ #endif
+ ])
++AC_CHECK_SIZEOF(size_t)
+ 
+ # add option to disable the evil rpath
+ ACX_ARG_RPATH
+diff --git a/contrib/create_unbound_ad_servers.sh b/contrib/create_unbound_ad_servers.sh
+index d31f078..49fdbff 100644
+--- a/contrib/create_unbound_ad_servers.sh
++++ b/contrib/create_unbound_ad_servers.sh
+@@ -9,12 +9,13 @@
+ # Variables
+ dst_dir="/etc/opt/csw/unbound"
+ work_dir="/tmp"
+-list_addr="http://pgl.yoyo.org/adservers/serverlist.php?hostformat=nohtml&showintro=1&startdate%5Bday%5D=&startdate%5Bmonth%5D=&startdate%5Byear%5D="
++list_addr="https://pgl.yoyo.org/adservers/serverlist.php?hostformat=nohtml&showintro=1&startdate%5Bday%5D=&startdate%5Bmonth%5D=&startdate%5Byear%5D="
+ 
+ # OS commands
+ CAT=`which cat`
+ ECHO=`which echo`
+ WGET=`which wget`
++TR=`which tr`
+ 
+ # Check Wget installed
+ if [ ! -f $WGET ]; then
+@@ -22,8 +23,10 @@ if [ ! -f $WGET ]; then
+  exit 1
+ fi
+ 
++# remove special characters with tr to protect unbound.conf
+ $WGET -O $work_dir/yoyo_ad_servers "$list_addr" && \
+ $CAT $work_dir/yoyo_ad_servers | \
++$TR -d '";$\\' | \
+ while read line ; \
+  do \
+    $ECHO "local-zone: \"$line\" redirect" ;\
+@@ -36,4 +39,4 @@ echo "Done."
+ #  the unbound_ad_servers file:
+ #
+ #   include: $dst_dir/unbound_ad_servers
+-#
+\ No newline at end of file
++#
+diff --git a/daemon/daemon.c b/daemon/daemon.c
+index 6820e11..1b4f329 100644
+--- a/daemon/daemon.c
++++ b/daemon/daemon.c
+@@ -426,9 +426,7 @@ daemon_create_workers(struct daemon* daemon)
+ 	int* shufport;
+ 	log_assert(daemon && daemon->cfg);
+ 	if(!daemon->rand) {
+-		unsigned int seed = (unsigned int)time(NULL) ^ 
+-			(unsigned int)getpid() ^ 0x438;
+-		daemon->rand = ub_initstate(seed, NULL);
++		daemon->rand = ub_initstate(NULL);
+ 		if(!daemon->rand)
+ 			fatal_exit("could not init random generator");
+ 		hash_set_raninit((uint32_t)ub_random(daemon->rand));
+diff --git a/daemon/worker.c b/daemon/worker.c
+index 3acecc1..8354010 100644
+--- a/daemon/worker.c
++++ b/daemon/worker.c
+@@ -1629,18 +1629,14 @@ worker_create(struct daemon* daemon, int id, int* ports, int n)
+ 		return NULL;
+ 	}
+ 	/* create random state here to avoid locking trouble in RAND_bytes */
+-	seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
+-		(((unsigned int)worker->thread_num)<<17);
+-		/* shift thread_num so it does not match out pid bits */
+-	if(!(worker->rndstate = ub_initstate(seed, daemon->rand))) {
+-		seed = 0;
++	if(!(worker->rndstate = ub_initstate(daemon->rand))) {
+ 		log_err("could not init random numbers.");
+ 		tube_delete(worker->cmd);
+ 		free(worker->ports);
+ 		free(worker);
+ 		return NULL;
+ 	}
+-	seed = 0;
++	explicit_bzero(&seed, sizeof(seed));
+ #ifdef USE_DNSTAP
+ 	if(daemon->cfg->dnstap) {
+ 		log_assert(daemon->dtenv != NULL);
+diff --git a/dns64/dns64.c b/dns64/dns64.c
+index 7889d72..300202c 100644
+--- a/dns64/dns64.c
++++ b/dns64/dns64.c
+@@ -782,6 +782,16 @@ dns64_inform_super(struct module_qstate* qstate, int id,
+ 	 * Signal that the sub-query is finished, no matter whether we are
+ 	 * successful or not. This lets the state machine terminate.
+ 	 */
++	if(!super->minfo[id]) {
++		super->minfo[id] = (enum dns64_qstate *)regional_alloc(super->region,
++			sizeof(*(super->minfo[id])));
++		if(!super->minfo[id]) {
++			log_err("out of memory");
++			super->return_rcode = LDNS_RCODE_SERVFAIL;
++			super->return_msg = NULL;
++			return;
++		}
++	}
+	super->minfo[id] = (void*)DNS64_SUBQUERY_FINISHED;
+ 
+ 	/* If there is no successful answer, we're done. */
+diff --git a/dnscrypt/dnscrypt.c b/dnscrypt/dnscrypt.c
+index 3545d3d..7dd2ce5 100644
+--- a/dnscrypt/dnscrypt.c
++++ b/dnscrypt/dnscrypt.c
+@@ -732,6 +732,11 @@ dnsc_load_local_data(struct dnsc_env* dnscenv, struct config_file *cfg)
+             );
+             continue;
+         }
++        if((unsigned)strlen(dnscenv->provider_name) >= (unsigned)0xffff0000) {
++		    /* guard against integer overflow in rrlen calculation */
++		    verbose(VERB_OPS, "cert #%" PRIu32 " is too long", serial);
++		    continue;
++        }
+         rrlen = strlen(dnscenv->provider_name) +
+                          strlen(ttl_class_type) +
+                          4 * sizeof(struct SignedCert) + // worst case scenario
+diff --git a/doc/Changelog b/doc/Changelog
+index bb74461..4cb080e 100644
+--- a/doc/Changelog
++++ b/doc/Changelog
+@@ -1,3 +1,55 @@
++3 December 2019: Wouter
++	- Fix Assert Causing DoS in synth_cname(),
++	  reported by X41 D-Sec.
++	- Fix Assert Causing DoS in dname_pkt_copy(),
++	  reported by X41 D-Sec.
++	- Fix OOB Read in sldns_wire2str_dname_scan(),
++	  reported by X41 D-Sec.
++	- Fix Out of Bounds Write in sldns_str2wire_str_buf(),
++	  reported by X41 D-Sec.
++	- Fix Out of Bounds Write in sldns_b64_pton(),
++	  fixed by check in sldns_str2wire_int16_data_buf(),
++	  reported by X41 D-Sec.
++	- Fix Insufficient Handling of Compressed Names in dname_pkt_copy(),
++	  reported by X41 D-Sec.
++	- Fix Out of Bound Write Compressed Names in rdata_copy(),
++	  reported by X41 D-Sec.
++	- Fix Hang in sldns_wire2str_pkt_scan(),
++	  reported by X41 D-Sec.
++
++20 November 2019: Wouter
++	- Fix Out of Bounds Read in rrinternal_get_owner(),
++	  reported by X41 D-Sec.
++	- Fix Race Condition in autr_tp_create(),
++	  reported by X41 D-Sec.
++	- Fix Shared Memory World Writeable,
++	  reported by X41 D-Sec.
++	- Adjust unbound-control to make stats_shm a read only operation.
++	- Fix Weak Entropy Used For Nettle,
++	  reported by X41 D-Sec.
++	- Fix Randomness Error not Handled Properly,
++	  reported by X41 D-Sec.
++	- Fix Out-of-Bounds Read in dname_valid(),
++	  reported by X41 D-Sec.
++	- Fix Config Injection in create_unbound_ad_servers.sh,
++	  reported by X41 D-Sec.
++
++19 November 2019: Wouter
++	- Fix Integer Overflow in Regional Allocator,
++	  reported by X41 D-Sec.
++	- Fix Unchecked NULL Pointer in dns64_inform_super()
++	  and ipsecmod_new(), reported by X41 D-Sec.
++	- Fix Out-of-bounds Read in rr_comment_dnskey(),
++	  reported by X41 D-Sec.
++	- Fix Integer Overflows in Size Calculations,
++	  reported by X41 D-Sec.
++	- Fix Integer Overflow to Buffer Overflow in
++	  sldns_str2wire_dname_buf_origin(), reported by X41 D-Sec.
++	- Fix Out of Bounds Read in sldns_str2wire_dname(),
++	  reported by X41 D-Sec.
++	- Fix Out of Bounds Write in sldns_bget_token_par(),
++	  reported by X41 D-Sec.
++
+ 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.
+diff --git a/ipsecmod/ipsecmod.c b/ipsecmod/ipsecmod.c
+index 3572f12..1422a62 100644
+--- a/ipsecmod/ipsecmod.c
++++ b/ipsecmod/ipsecmod.c
+@@ -103,11 +103,11 @@ ipsecmod_new(struct module_qstate* qstate, int id)
+ {
+ 	struct ipsecmod_qstate* iq = (struct ipsecmod_qstate*)regional_alloc(
+ 		qstate->region, sizeof(struct ipsecmod_qstate));
+-	memset(iq, 0, sizeof(*iq));
+ 	qstate->minfo[id] = iq;
+ 	if(!iq)
+ 		return 0;
+ 	/* Initialise it. */
++	memset(iq, 0, sizeof(*iq));
+ 	iq->enabled = qstate->env->cfg->ipsecmod_enabled;
+ 	iq->is_whitelisted = ipsecmod_domain_is_whitelisted(
+ 		(struct ipsecmod_env*)qstate->env->modinfo[id], qstate->qinfo.qname,
+diff --git a/iterator/iter_scrub.c b/iterator/iter_scrub.c
+index 8230d17..942c3d5 100644
+--- a/iterator/iter_scrub.c
++++ b/iterator/iter_scrub.c
+@@ -231,6 +231,10 @@ synth_cname(uint8_t* qname, size_t qnamelen, struct rrset_parse* dname_rrset,
+ 	size_t dtarglen;
+ 	if(!parse_get_cname_target(dname_rrset, &dtarg, &dtarglen, pkt))
+ 		return 0; 
++	if(qnamelen <= dname_rrset->dname_len)
++		return 0;
++	if(qnamelen == 0)
++		return 0;
+ 	log_assert(qnamelen > dname_rrset->dname_len);
+ 	/* DNAME from com. to net. with qname example.com. -> example.net. */
+ 	/* so: \3com\0 to \3net\0 and qname \7example\3com\0 */
+diff --git a/libunbound/libunbound.c b/libunbound/libunbound.c
+index 275e8d2..a8979c2 100644
+--- a/libunbound/libunbound.c
++++ b/libunbound/libunbound.c
+@@ -83,7 +83,6 @@
+ static struct ub_ctx* ub_ctx_create_nopipe(void)
+ {
+ 	struct ub_ctx* ctx;
+-	unsigned int seed;
+ #ifdef USE_WINSOCK
+ 	int r;
+ 	WSADATA wsa_data;
+@@ -107,15 +106,12 @@ static struct ub_ctx* ub_ctx_create_nopipe(void)
+ 		return NULL;
+ 	}
+ 	alloc_init(&ctx->superalloc, NULL, 0);
+-	seed = (unsigned int)time(NULL) ^ (unsigned int)getpid();
+-	if(!(ctx->seed_rnd = ub_initstate(seed, NULL))) {
+-		seed = 0;
++	if(!(ctx->seed_rnd = ub_initstate(NULL))) {
+ 		ub_randfree(ctx->seed_rnd);
+ 		free(ctx);
+ 		errno = ENOMEM;
+ 		return NULL;
+ 	}
+-	seed = 0;
+ 	lock_basic_init(&ctx->qqpipe_lock);
+ 	lock_basic_init(&ctx->rrpipe_lock);
+ 	lock_basic_init(&ctx->cfglock);
+diff --git a/libunbound/libworker.c b/libunbound/libworker.c
+index 3dcaa78..07a08c6 100644
+--- a/libunbound/libworker.c
++++ b/libunbound/libworker.c
+@@ -122,7 +122,6 @@ libworker_delete_event(struct libworker* w)
+ static struct libworker*
+ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
+ {
+-	unsigned int seed;
+ 	struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
+ 	struct config_file* cfg = ctx->env->cfg;
+ 	int* ports;
+@@ -177,17 +176,13 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
+ 	}
+ 	w->env->worker = (struct worker*)w;
+ 	w->env->probe_timer = NULL;
+-	seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
+-		(((unsigned int)w->thread_num)<<17);
+-	seed ^= (unsigned int)w->env->alloc->next_id;
+ 	if(!w->is_bg || w->is_bg_thread) {
+ 		lock_basic_lock(&ctx->cfglock);
+ 	}
+-	if(!(w->env->rnd = ub_initstate(seed, ctx->seed_rnd))) {
++	if(!(w->env->rnd = ub_initstate(ctx->seed_rnd))) {
+ 		if(!w->is_bg || w->is_bg_thread) {
+ 			lock_basic_unlock(&ctx->cfglock);
+ 		}
+-		seed = 0;
+ 		libworker_delete(w);
+ 		return NULL;
+ 	}
+@@ -207,7 +202,6 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
+ 			hash_set_raninit((uint32_t)ub_random(w->env->rnd));
+ 		}
+ 	}
+-	seed = 0;
+ 
+ 	if(eb)
+ 		w->base = comm_base_create_event(eb);
+diff --git a/respip/respip.c b/respip/respip.c
+index 2e9313f..7d2a588 100644
+--- a/respip/respip.c
++++ b/respip/respip.c
+@@ -475,10 +475,16 @@ copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region)
+ 	if(!ck->rk.dname)
+ 		return NULL;
+ 
++	if((unsigned)data->count >= 0xffff00U)
++		return NULL; /* guard against integer overflow in dsize */
+ 	dsize = sizeof(struct packed_rrset_data) + data->count *
+ 		(sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t));
+-	for(i=0; i<data->count; i++)
++	for(i=0; i<data->count; i++) {
++		if((unsigned)dsize >= 0x0fffffffU ||
++			(unsigned)data->rr_len[i] >= 0x0fffffffU)
++			return NULL; /* guard against integer overflow */
+ 		dsize += data->rr_len[i];
++	}
+ 	d = regional_alloc(region, dsize);
+ 	if(!d)
+ 		return NULL;
+diff --git a/sldns/parse.c b/sldns/parse.c
+index b62c405..b30264e 100644
+--- a/sldns/parse.c
++++ b/sldns/parse.c
+@@ -325,8 +325,14 @@ sldns_bget_token_par(sldns_buffer *b, char *token, const char *delim,
+ 		if (c == '\n' && p != 0) {
+ 			/* in parentheses */
+ 			/* do not write ' ' if we want to skip spaces */
+-			if(!(skipw && (strchr(skipw, c)||strchr(skipw, ' '))))
++			if(!(skipw && (strchr(skipw, c)||strchr(skipw, ' ')))) {
++				/* check for space for the space character */
++				if (limit > 0 && (i >= limit || (size_t)(t-token) >= limit)) {
++					*t = '\0';
++					return -1;
++				}
+ 				*t++ = ' ';
++			}
+ 			lc = c;
+ 			continue;
+ 		}
+diff --git a/sldns/str2wire.c b/sldns/str2wire.c
+index 1a51bb6..414b7b8 100644
+--- a/sldns/str2wire.c
++++ b/sldns/str2wire.c
+@@ -150,6 +150,10 @@ int sldns_str2wire_dname_buf_origin(const char* str, uint8_t* buf, size_t* len,
+ 	if(s) return s;
+ 
+ 	if(rel && origin && dlen > 0) {
++		if((unsigned)dlen >= 0x00ffffffU ||
++			(unsigned)origin_len >= 0x00ffffffU)
++			/* guard against integer overflow in addition */
++			return RET_ERR(LDNS_WIREPARSE_ERR_GENERAL, *len);
+ 		if(dlen + origin_len - 1 > LDNS_MAX_DOMAINLEN)
+ 			return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW,
+ 				LDNS_MAX_DOMAINLEN);
+@@ -168,7 +172,9 @@ uint8_t* sldns_str2wire_dname(const char* str, size_t* len)
+ 	uint8_t dname[LDNS_MAX_DOMAINLEN+1];
+ 	*len = sizeof(dname);
+ 	if(sldns_str2wire_dname_buf(str, dname, len) == 0) {
+-		uint8_t* r = (uint8_t*)malloc(*len);
++		uint8_t* r;
++		if(*len > sizeof(dname)) return NULL;
++		r = (uint8_t*)malloc(*len);
+ 		if(r) return memcpy(r, dname, *len);
+ 	}
+ 	*len = 0;
+@@ -187,6 +193,9 @@ rrinternal_get_owner(sldns_buffer* strbuf, uint8_t* rr, size_t* len,
+ 			sldns_buffer_position(strbuf));
+ 	}
+ 
++	if(token_len < 2) /* make sure there is space to read "@" or "" */
++		return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
++			sldns_buffer_position(strbuf));
+ 	if(strcmp(token, "@") == 0) {
+ 		uint8_t* tocopy;
+ 		if (origin) {
+@@ -1094,7 +1103,7 @@ int sldns_str2wire_str_buf(const char* str, uint8_t* rd, size_t* len)
+ 	while(sldns_parse_char(&ch, &s)) {
+ 		if(sl >= 255)
+ 			return RET_ERR(LDNS_WIREPARSE_ERR_INVALID_STR, s-str);
+-		if(*len < sl+1)
++		if(*len < sl+2)
+ 			return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL,
+ 				s-str);
+ 		rd[++sl] = ch;
+@@ -2095,6 +2104,8 @@ int sldns_str2wire_int16_data_buf(const char* str, uint8_t* rd, size_t* len)
+ 	char* s;
+ 	int n;
+ 	n = strtol(str, &s, 10);
++	if(n < 0) /* negative number not allowed */
++		return LDNS_WIREPARSE_ERR_SYNTAX;
+ 	if(*len < ((size_t)n)+2)
+ 		return LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL;
+ 	if(n > 65535)
+diff --git a/sldns/wire2str.c b/sldns/wire2str.c
+index 832239f..a95c9b3 100644
+--- a/sldns/wire2str.c
++++ b/sldns/wire2str.c
+@@ -585,6 +585,7 @@ static int rr_comment_dnskey(char** s, size_t* slen, uint8_t* rr,
+ 	if(rrlen < dname_off + 10) return 0;
+ 	rdlen = sldns_read_uint16(rr+dname_off+8);
+ 	if(rrlen < dname_off + 10 + rdlen) return 0;
++	if(rdlen < 2) return 0;
+ 	rdata = rr + dname_off + 10;
+ 	flags = (int)sldns_read_uint16(rdata);
+ 	w += sldns_str_print(s, slen, " ;{");
+@@ -781,7 +782,7 @@ int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
+ 	/* spool labels onto the string, use compression if its there */
+ 	uint8_t* pos = *d;
+ 	unsigned i, counter=0;
+-	const unsigned maxcompr = 1000; /* loop detection, max compr ptrs */
++	const unsigned maxcompr = 256; /* loop detection, max compr ptrs */
+ 	int in_buf = 1;
+ 	if(*dlen == 0) return sldns_str_print(s, slen, "ErrorMissingDname");
+ 	if(*pos == 0) {
+@@ -789,7 +790,7 @@ int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
+ 		(*dlen)--;
+ 		return sldns_str_print(s, slen, ".");
+ 	}
+-	while(*pos) {
++	while((!pkt || pos < pkt+pktlen) && *pos) {
+ 		/* read label length */
+ 		uint8_t labellen = *pos++;
+ 		if(in_buf) { (*d)++; (*dlen)--; }
+diff --git a/smallapp/unbound-control.c b/smallapp/unbound-control.c
+index d165417..2884309 100644
+--- a/smallapp/unbound-control.c
++++ b/smallapp/unbound-control.c
+@@ -407,19 +407,19 @@ static void print_stats_shm(const char* cfgfile)
+ 	if(!config_read(cfg, cfgfile, NULL))
+ 		fatal_exit("could not read config file");
+ 	/* get shm segments */
+-	id_ctl = shmget(cfg->shm_key, sizeof(int), SHM_R|SHM_W);
++	id_ctl = shmget(cfg->shm_key, sizeof(int), SHM_R);
+ 	if(id_ctl == -1) {
+ 		fatal_exit("shmget(%d): %s", cfg->shm_key, strerror(errno));
+ 	}
+-	id_arr = shmget(cfg->shm_key+1, sizeof(int), SHM_R|SHM_W);
++	id_arr = shmget(cfg->shm_key+1, sizeof(int), SHM_R);
+ 	if(id_arr == -1) {
+ 		fatal_exit("shmget(%d): %s", cfg->shm_key+1, strerror(errno));
+ 	}
+-	shm_stat = (struct ub_shm_stat_info*)shmat(id_ctl, NULL, 0);
++	shm_stat = (struct ub_shm_stat_info*)shmat(id_ctl, NULL, SHM_RDONLY);
+ 	if(shm_stat == (void*)-1) {
+ 		fatal_exit("shmat(%d): %s", id_ctl, strerror(errno));
+ 	}
+-	stats = (struct ub_stats_info*)shmat(id_arr, NULL, 0);
++	stats = (struct ub_stats_info*)shmat(id_arr, NULL, SHM_RDONLY);
+ 	if(stats == (void*)-1) {
+ 		fatal_exit("shmat(%d): %s", id_arr, strerror(errno));
+ 	}
+diff --git a/testcode/unitmain.c b/testcode/unitmain.c
+index fecde80..96a6654 100644
+--- a/testcode/unitmain.c
++++ b/testcode/unitmain.c
+@@ -537,10 +537,8 @@ rnd_test(void)
+ 	struct ub_randstate* r;
+ 	int num = 1000, i;
+ 	long int a[1000];
+-	unsigned int seed = (unsigned)time(NULL);
+ 	unit_show_feature("ub_random");
+-	printf("ub_random seed is %u\n", seed);
+-	unit_assert( (r = ub_initstate(seed, NULL)) );
++	unit_assert( (r = ub_initstate(NULL)) );
+ 	for(i=0; i<num; i++) {
+ 		a[i] = ub_random(r);
+ 		unit_assert(a[i] >= 0);
+diff --git a/util/data/dname.c b/util/data/dname.c
+index b744f06..923be02 100644
+--- a/util/data/dname.c
++++ b/util/data/dname.c
+@@ -75,6 +75,8 @@ dname_valid(uint8_t* dname, size_t maxlen)
+ {
+ 	size_t len = 0;
+ 	size_t labellen;
++	if(maxlen == 0)
++		return 0; /* too short, shortest is '0' root label */
+ 	labellen = *dname++;
+ 	while(labellen) {
+ 		if(labellen&0xc0)
+@@ -345,11 +347,17 @@ dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_type h)
+ void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
+ {
+ 	/* copy over the dname and decompress it at the same time */
++	size_t comprcount = 0;
+ 	size_t len = 0;
+ 	uint8_t lablen;
+ 	lablen = *dname++;
+ 	while(lablen) {
+ 		if(LABEL_IS_PTR(lablen)) {
++			if(comprcount++ > MAX_COMPRESS_PTRS) {
++				/* too many compression pointers */
++				*to = 0; /* end the result prematurely */
++				return;
++			}
+ 			/* follow pointer */
+             if((size_t)PTR_OFFSET(lablen, *dname)
+                 >= sldns_buffer_limit(pkt))
+@@ -358,6 +366,10 @@ void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
+ 			lablen = *dname++;
+ 			continue;
+ 		}
++		if(lablen > LDNS_MAX_LABELLEN) {
++			*to = 0; /* end the result prematurely */
++			return;
++		}
+ 		log_assert(lablen <= LDNS_MAX_LABELLEN);
+ 		len += (size_t)lablen+1;
+ 		if(len >= LDNS_MAX_DOMAINLEN) {
+diff --git a/util/data/msgreply.c b/util/data/msgreply.c
+index df2131c..dbae34d 100644
+--- a/util/data/msgreply.c
++++ b/util/data/msgreply.c
+@@ -238,10 +238,10 @@ rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
+ 				break;
+ 			}
+ 			if(len) {
++				log_assert(len <= pkt_len);
+ 				memmove(to, sldns_buffer_current(pkt), len);
+ 				to += len;
+ 				sldns_buffer_skip(pkt, (ssize_t)len);
+-				log_assert(len <= pkt_len);
+ 				pkt_len -= len;
+ 			}
+ 			rdf++;
+diff --git a/util/random.c b/util/random.c
+index 8332960..9380502 100644
+--- a/util/random.c
++++ b/util/random.c
+@@ -86,8 +86,7 @@ ub_systemseed(unsigned int ATTR_UNUSED(seed))
+ }
+ 
+ struct ub_randstate* 
+-ub_initstate(unsigned int ATTR_UNUSED(seed),
+-	struct ub_randstate* ATTR_UNUSED(from))
++ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
+ {
+ 	struct ub_randstate* s = (struct ub_randstate*)malloc(1);
+ 	if(!s) {
+@@ -123,8 +122,8 @@ void ub_systemseed(unsigned int ATTR_UNUSED(seed))
+ {
+ }
+ 
+-struct ub_randstate* ub_initstate(unsigned int ATTR_UNUSED(seed), 
+-	struct ub_randstate* ATTR_UNUSED(from))
++struct ub_randstate* 
++ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
+ {
+ 	struct ub_randstate* s = (struct ub_randstate*)calloc(1, sizeof(*s));
+ 	if(!s) {
+@@ -140,7 +139,9 @@ long int ub_random(struct ub_randstate* ATTR_UNUSED(state))
+ 	/* random 31 bit value. */
+ 	SECStatus s = PK11_GenerateRandom((unsigned char*)&x, (int)sizeof(x));
+ 	if(s != SECSuccess) {
+-		log_err("PK11_GenerateRandom error: %s",
++		/* unbound needs secure randomness for randomized
++		 * ID bits and port numbers in packets to upstream servers */
++		fatal_exit("PK11_GenerateRandom error: %s",
+ 			PORT_ErrorToString(PORT_GetError()));
+ 	}
+ 	return x & MAX_VALUE;
+@@ -166,8 +167,7 @@ void ub_systemseed(unsigned int ATTR_UNUSED(seed))
+ 	log_err("Re-seeding not supported, generator untouched");
+ }
+ 
+-struct ub_randstate* ub_initstate(unsigned int seed,
+-	struct ub_randstate* ATTR_UNUSED(from))
++struct ub_randstate* ub_initstate(struct ub_randstate* ATTR_UNUSED(from))
+ {
+ 	struct ub_randstate* s = (struct ub_randstate*)calloc(1, sizeof(*s));
+ 	uint8_t buf[YARROW256_SEED_FILE_SIZE];
+@@ -183,15 +183,10 @@ struct ub_randstate* ub_initstate(unsigned int seed,
+ 		yarrow256_seed(&s->ctx, YARROW256_SEED_FILE_SIZE, buf);
+ 		s->seeded = yarrow256_is_seeded(&s->ctx);
+ 	} else {
+-		/* Stretch the uint32 input seed and feed it to Yarrow */
+-		uint32_t v = seed;
+-		size_t i;
+-		for(i=0; i < (YARROW256_SEED_FILE_SIZE/sizeof(seed)); i++) {
+-			memmove(buf+i*sizeof(seed), &v, sizeof(seed));
+-			v = v*seed + (uint32_t)i;
+-		}
+-		yarrow256_seed(&s->ctx, YARROW256_SEED_FILE_SIZE, buf);
+-		s->seeded = yarrow256_is_seeded(&s->ctx);
++		log_err("nettle random(yarrow) cannot initialize, "
++			"getentropy failed: %s", strerror(errno));
++		free(s);
++		return NULL;
+ 	}
+ 
+ 	return s;
+diff --git a/util/random.h b/util/random.h
+index a05a994..e75157d 100644
+--- a/util/random.h
++++ b/util/random.h
+@@ -57,15 +57,12 @@ void ub_systemseed(unsigned int seed);
+ 
+ /**
+  * Initialize a random generator state for use 
+- * @param seed: seed value to create state contents.
+- *	(ignored for arc4random).
+  * @param from: if not NULL, the seed is taken from this random structure.
+  * 	can be used to seed random states via a parent-random-state that
+  * 	is itself seeded with entropy.
+  * @return new state or NULL alloc failure.
+  */
+-struct ub_randstate* ub_initstate(unsigned int seed, 
+-	struct ub_randstate* from);
++struct ub_randstate* ub_initstate(struct ub_randstate* from);
+ 
+ /**
+  * Generate next random number from the state passed along.
+diff --git a/util/regional.c b/util/regional.c
+index 899a54e..5be09eb 100644
+--- a/util/regional.c
++++ b/util/regional.c
+@@ -120,8 +120,18 @@ regional_destroy(struct regional *r)
+ void *
+ regional_alloc(struct regional *r, size_t size)
+ {
+-	size_t a = ALIGN_UP(size, ALIGNMENT);
++	size_t a;
+ 	void *s;
++	if(
++#if SIZEOF_SIZE_T == 8
++		(unsigned long long)size >= 0xffffffffffffff00ULL
++#else
++		(unsigned)size >= (unsigned)0xffffff00UL
++#endif
++		)
++		return NULL; /* protect against integer overflow in
++			malloc and ALIGN_UP */
++	a = ALIGN_UP(size, ALIGNMENT);
+ 	/* large objects */
+ 	if(a > REGIONAL_LARGE_OBJECT_SIZE) {
+ 		s = malloc(ALIGNMENT + size);
+diff --git a/util/shm_side/shm_main.c b/util/shm_side/shm_main.c
+index a783c09..69bee4d 100644
+--- a/util/shm_side/shm_main.c
++++ b/util/shm_side/shm_main.c
+@@ -121,7 +121,7 @@ int shm_main_init(struct daemon* daemon)
+ 		shmctl(daemon->shm_info->id_arr, IPC_RMID, NULL);
+ 
+ 	/* SHM: Create the segment */
+-	daemon->shm_info->id_ctl = shmget(daemon->shm_info->key, sizeof(struct ub_shm_stat_info), IPC_CREAT | 0666);
++	daemon->shm_info->id_ctl = shmget(daemon->shm_info->key, sizeof(struct ub_shm_stat_info), IPC_CREAT | 0644);
+ 
+ 	if (daemon->shm_info->id_ctl < 0)
+ 	{
+@@ -134,7 +134,7 @@ int shm_main_init(struct daemon* daemon)
+ 		return 0;
+ 	}
+ 
+-	daemon->shm_info->id_arr = shmget(daemon->shm_info->key + 1, shm_size, IPC_CREAT | 0666);
++	daemon->shm_info->id_arr = shmget(daemon->shm_info->key + 1, shm_size, IPC_CREAT | 0644);
+ 
+ 	if (daemon->shm_info->id_arr < 0)
+ 	{
+diff --git a/validator/autotrust.c b/validator/autotrust.c
+index 7bc5577..e19bd7b 100644
+--- a/validator/autotrust.c
++++ b/validator/autotrust.c
+@@ -370,10 +370,10 @@ autr_tp_create(struct val_anchors* anchors, uint8_t* own, size_t own_len,
+ 		free(tp);
+ 		return NULL;
+ 	}
+-	lock_basic_unlock(&anchors->lock);
+ 	lock_basic_init(&tp->lock);
+ 	lock_protect(&tp->lock, tp, sizeof(*tp));
+ 	lock_protect(&tp->lock, tp->autr, sizeof(*tp->autr));
++	lock_basic_unlock(&anchors->lock);
+ 	return tp;
+ }
+ 
diff --git a/SOURCES/unbound-1.7.3-symlink-traversal.patch b/SOURCES/unbound-1.7.3-symlink-traversal.patch
new file mode 100644
index 0000000..0c06794
--- /dev/null
+++ b/SOURCES/unbound-1.7.3-symlink-traversal.patch
@@ -0,0 +1,43 @@
+diff --git a/unbound-1.7.3/daemon/unbound.c b/unbound-1.7.3/daemon/unbound.c
+index 1383110..66ed61d 100644
+--- a/daemon/unbound.c
++++ b/daemon/unbound.c
+@@ -327,18 +327,32 @@ readpid (const char* file)
+ static void
+ writepid (const char* pidfile, pid_t pid)
+ {
+-	FILE* f;
++	int fd;
++	char pidbuf[32];
++	size_t count = 0;
++	snprintf(pidbuf, sizeof(pidbuf), "%lu\n", (unsigned long)pid);
+ 
+-	if ((f = fopen(pidfile, "w")) ==  NULL ) {
++    if((fd = open(pidfile, O_WRONLY | O_CREAT | O_TRUNC
++#ifdef O_NOFOLLOW
++		| O_NOFOLLOW
++#endif
++		, 0644)) == -1) {
+ 		log_err("cannot open pidfile %s: %s", 
+ 			pidfile, strerror(errno));
+ 		return;
+ 	}
+-	if(fprintf(f, "%lu\n", (unsigned long)pid) < 0) {
+-		log_err("cannot write to pidfile %s: %s", 
+-			pidfile, strerror(errno));
++    while(count < strlen(pidbuf)) {
++		ssize_t r = write(fd, pidbuf+count, strlen(pidbuf)-count);
++		if(r == -1) {
++			if(errno == EAGAIN || errno == EINTR)
++				continue;
++			log_err("cannot write to pidfile %s: %s",
++				pidfile, strerror(errno));
++			break;
++		}
++		count += r;
+ 	}
+-	fclose(f);
++	close(fd);
+ }
+ 
+ /**
diff --git a/SPECS/unbound.spec b/SPECS/unbound.spec
index 9a37167..f67eb73 100644
--- a/SPECS/unbound.spec
+++ b/SPECS/unbound.spec
@@ -34,7 +34,7 @@
 Summary: Validating, recursive, and caching DNS(SEC) resolver
 Name: unbound
 Version: 1.7.3
-Release: 14%{?extra_version:.%{extra_version}}%{?dist}
+Release: 15%{?extra_version:.%{extra_version}}%{?dist}
 License: BSD
 Url: https://www.unbound.net/
 Source: https://www.unbound.net/downloads/%{name}-%{version}%{?extra_version}.tar.gz
@@ -65,9 +65,14 @@ Patch8: unbound-1.7.3-auth-callback.patch
 Patch9: unbound-1.7.3-ksk-2010-revoked.patch
 Patch10: unbound-1.7.3-DNS-over-TLS-memory-leak.patch
 Patch11: unbound-1.7.3-amplifying-an-incoming-query.patch
+Patch12: unbound-1.7.3-crypto-policy-non-compliance-openssl.patch
+Patch13: unbound-1.7.3-additional-logging.patch
+Patch14: unbound-1.7.3-security-hardening.patch
+Patch15: unbound-1.7.3-symlink-traversal.patch
 
+BuildRequires: gdb
 BuildRequires: gcc, make
-BuildRequires: flex, openssl-devel
+BuildRequires: byacc, flex, openssl-devel
 BuildRequires: libevent-devel expat-devel
 BuildRequires: pkgconfig
 %if 0%{with_python2}
@@ -170,6 +175,10 @@ pushd %{pkgname}
 %patch9 -p1 -b .ksk-2010-revoked
 %patch10 -p1 -b .DNS-over-TLS-memory-leak
 %patch11 -p1 -b .amplifying-an-incoming-query
+%patch12 -p1 -b .crypto-policy
+%patch13 -p1 -b .additional-logging
+%patch14 -p1 -b .security-hardening
+%patch15 -p1 -b .symlink-traversal
 
 # only for snapshots
 # autoreconf -iv
@@ -439,8 +448,22 @@ popd
 %attr(0644,unbound,unbound) %config %{_sharedstatedir}/%{name}/root.key
 # just left for backwards compat with user changed unbound.conf files - format is different!
 %attr(0644,root,root) %config %{_sysconfdir}/%{name}/root.key
+# modification of root.key is maintained by unbound-achor.service and is intentional, so let rpm know
+%verify(not md5 size mtime) %{_sharedstatedir}/%{name}/root.key
 
 %changelog
+* Tue Sep 01 2020 Anna Khaitovich <akhaitov@redhat.com> - 1.7.3-15
+- Fix SPEC file to not check md5 mtime and size of /var/lib/unbound/root.key
+- Resolves: rhbz#1714175
+- Use system-wide crypto policy setting (PROFILE=SYSTEM) instead of custom setting
+- Resolves: rhbz#1842837
+- Enable additional logging in unbound
+- Resolves: rhbz#1850460
+- security hardening from x41 report
+- Resolves: rhbz#1859933
+- symbolic link traversal when writing PID file
+- Resolves: rhbz#1899058
+
 * Thu May 28 2020 Anna Khaitovich <akhaitov@redhat.com> - 1.7.3-14
 - Fix unbound-1.7.3-amplifying-an-incoming-query.patch patch
 - Resolves: rhbz#1839178 (CVE-2020-12662)