]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix to print details about the failure to lookup a DNSKEY record
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 4 Jul 2024 12:51:18 +0000 (14:51 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Thu, 4 Jul 2024 12:51:18 +0000 (14:51 +0200)
  when validation fails due to the missing DNSKEY. Also for key prime
  and DS lookups.

doc/Changelog
testdata/val_failure_dnskey.rpl [new file with mode: 0644]
validator/validator.c

index 325285337e7cb7aa37bb941ffe0158b7dc1aa560..2a7cb870d6f2bc65401b46fcefc83f43dd02f9ab 100644 (file)
@@ -1,3 +1,8 @@
+4 July 2024: Wouter
+       - Fix to print details about the failure to lookup a DNSKEY record
+         when validation fails due to the missing DNSKEY. Also for key prime
+         and DS lookups.
+
 3 July 2024: Yorgos
        - Fix for repeated use of a DNAME record: first overallocate and then
          move the exact size of the init value to avoid false positive heap
diff --git a/testdata/val_failure_dnskey.rpl b/testdata/val_failure_dnskey.rpl
new file mode 100644 (file)
index 0000000..3f25f15
--- /dev/null
@@ -0,0 +1,348 @@
+; config options
+; The island of trust is at example.com
+server:
+       trust-anchor: "example.com.    3600    IN      DS      2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b"
+       trust-anchor: "example.net.     3600    IN      DS      1444 8 2 69887be92d4848c0bc10acc95682a01e7e3b57ab0750a2ee6f72cac7191a64f1"
+       val-override-date: "20070916134226"
+       target-fetch-policy: "0 0 0 0 0"
+       qname-minimisation: "no"
+       fake-sha1: yes
+       trust-anchor-signaling: no
+       minimal-responses: no
+       log-servfail: yes
+       val-log-level: 2
+       ede: yes
+
+stub-zone:
+       name: "."
+       stub-addr: 193.0.14.129         # K.ROOT-SERVERS.NET.
+CONFIG_END
+
+SCENARIO_BEGIN Test validator with failure for chaing of trust lookup.
+; The error message that is created, also for EDE is more extensive.
+
+; K.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+       ADDRESS 193.0.14.129 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. IN NS        K.ROOT-SERVERS.NET.
+SECTION ADDITIONAL
+K.ROOT-SERVERS.NET.    IN      A       193.0.14.129
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION AUTHORITY
+com.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+net. IN NS
+SECTION AUTHORITY
+net.   IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.    IN      A       192.5.6.30
+ENTRY_END
+RANGE_END
+
+; a.gtld-servers.net.
+RANGE_BEGIN 0 100
+       ADDRESS 192.5.6.30
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com.    IN NS   a.gtld-servers.net.
+SECTION ADDITIONAL
+a.gtld-servers.net.     IN      A       192.5.6.30
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR NOERROR
+SECTION QUESTION
+example.net. IN NS
+SECTION AUTHORITY
+example.net.   IN NS   ns.example.net.
+SECTION ADDITIONAL
+ns.example.net.                IN      A       1.2.3.5
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.4
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+example.com. IN NS
+SECTION ANSWER
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN A
+SECTION ANSWER
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.com. IN AAAA
+SECTION AUTHORITY
+example.com.    IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.         IN      A       1.2.3.4
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+ENTRY_END
+
+; response to DNSKEY priming query
+;ENTRY_BEGIN
+;MATCH opcode qtype qname
+;ADJUST copy_id
+;REPLY QR NOERROR
+;SECTION QUESTION
+;example.com. IN DNSKEY
+;SECTION ANSWER
+;example.com.    3600    IN      DNSKEY  256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}
+;example.com.    3600    IN      RRSIG   DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854}
+;SECTION AUTHORITY
+;example.com.  IN NS   ns.example.com.
+;example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+;SECTION ADDITIONAL
+;ns.example.com.               IN      A       1.2.3.4
+;ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854}
+;ENTRY_END
+; servfail for DNSKEY priming query
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA SERVFAIL
+SECTION QUESTION
+example.com. IN DNSKEY
+ENTRY_END
+
+; response to query of interest
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+www.example.com. IN A  10.20.30.40
+ns.example.com. 3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854}
+SECTION AUTHORITY
+example.com.   IN NS   ns.example.com.
+example.com.    3600    IN      RRSIG   NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854}
+SECTION ADDITIONAL
+ns.example.com.                IN      A       1.2.3.4
+www.example.com.        3600    IN      RRSIG   A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854}
+ENTRY_END
+RANGE_END
+
+; ns.example.com.
+RANGE_BEGIN 0 100
+       ADDRESS 1.2.3.5
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.net. IN NS
+SECTION ANSWER
+example.net.   3600    IN      NS      ns.example.net.
+example.net.   3600    IN      RRSIG   NS 8 2 3600 20070926134150 20070829134150 1444 example.net. nHpOqZb00nIGytQ1YmVoXEHURL/75dWhlKSEtRTorjVdPGPZNN7ziCWJW303v7u07TkZ+i6oFVEWG/SDR4ejn5o31UKJy1373PEH/cvPf9/44jw9gAFaHF1eO6ZQGaRQaeEpU06+xUcnc2QXFt6rNu60EsTvMRDN83bD+r7FA7Y=
+SECTION ADDITIONAL
+ns.example.net.        3600    IN      A       1.2.3.5
+ns.example.net.        3600    IN      RRSIG   A 8 3 3600 20070926134150 20070829134150 1444 example.net. TgQ4nfGtLHuZXlC4JJlVQ6mejf1WJbstTxsh/kgMAc2tryOxF/gvGBHaMtz6oceFZrIgk6g3RYI1Gk5gjSFNADh+EIwI422M8XPAAxRLfFahiO4lr1aCo4c94TYeZNpnDKy81rINTz2hQE1pGWr8Z03ySABqSBnTE1FQt4N/JCo=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.net. IN A
+SECTION ANSWER
+ns.example.net.        3600    IN      A       1.2.3.5
+ns.example.net.        3600    IN      RRSIG   A 8 3 3600 20070926134150 20070829134150 1444 example.net. TgQ4nfGtLHuZXlC4JJlVQ6mejf1WJbstTxsh/kgMAc2tryOxF/gvGBHaMtz6oceFZrIgk6g3RYI1Gk5gjSFNADh+EIwI422M8XPAAxRLfFahiO4lr1aCo4c94TYeZNpnDKy81rINTz2hQE1pGWr8Z03ySABqSBnTE1FQt4N/JCo=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+ns.example.net. IN AAAA
+SECTION AUTHORITY
+example.net.   3600    IN      SOA     ns.example.net. host.example.net. 1 3600 300 7200 3600
+example.net.   3600    IN      RRSIG   SOA 8 2 3600 20070926134150 20070829134150 1444 example.net. P5FRQ4A/0n5owaBhZqlYBFD2PNAWJc5oxiDwvwh0hdjxETx8ta3EAvDKtNj5XZ5EKDAhP/tivd+Bq50I0xfRBmrouxgxjgnV3ye8zU+M1fXbuKpsWme9R3S4cs9WYfggTn7X00Af8m0tE62SLH/ZtOOQi2CvOPu7PXtHYT6KW4Q=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+example.net. IN DNSKEY
+SECTION ANSWER
+example.net.   3600    IN      DNSKEY  257 3 8 AwEAAbd9WqjzE2Pynz21OG5doSf9hFzMr5dhzz2waZ3vTa+0o5r7AjTAqmA1yH/B3+aAMihUm5ucZSfVqo7+kOaRE8yFj9aivOmA1n1+JLevJq/oyvQyjxQN2Qb89LyaNUT5oKZIiL+uyyhNW3KDR3SSbQ/GBwQNDHVcZi+JDR3RC0r7 ;{id = 1444 (ksk), size = 1024b}
+example.net.   3600    IN      RRSIG   DNSKEY 8 2 3600 20070926134150 20070829134150 1444 example.net. hAAlJt/YwAgWBzseK0N42+ysSMaWgntcuftF8a43chLh+fbe3vPWrgwqr/Cic52tu4ZqMox592tqWDxAG7F1eDGfO0SfzS2C9Tc/Wnz5nFjFh75G4Mtt8DTv5vTyGUVX5zAFzV8SNijVC0o1F7MHaVPt3rFtjjg2zW/UOz2m9+U=
+ENTRY_END
+
+; For sub1.example.net. zone; it is co-hosted with example.net, so that
+; there can be failures for the DS lookup. But the data lookup succeeds.
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+www.sub1.example.net. IN A
+SECTION ANSWER
+www.sub1.example.net. IN A     10.20.30.41
+www.sub1.example.net.  3600    IN      RRSIG   A 8 4 3600 20070926134150 20070829134150 29332 sub1.example.net. NcFP77Hixawt8hb+STIbbeqdF9tWTuHsbGEB4agKXlwHqS0BnyA+It6+UdE57IF0Kbnc7gSuaslX9At8ctd4HuC/9F/osbo96o23JEfnXPky/r5SsLaeN5KmUmUVjG9oxyAEc6PVlaaQ5a/RhaxmDRaDiku2gB7KjdjPxwxe+Rc54GV2eM3GtcfT+oDakLdSSACqeVjUFIOtYMpG8jAHrBe4uSnjKI7O0fWDFN5OES6sN9iUS9/ceorIoF/gSIqM7xWEuPLxE2c5TtYJyPtMCeGJ9wBP4wrTXfJ58+Lg5SFKgEuKTvAqEv9KEwg/kJb1GQ+ho5XKFO6EII2iyeUK/w==
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR SERVFAIL
+SECTION QUESTION
+sub1.example.net. IN DS
+SECTION ANSWER
+; no DS for sub1.example.net id=29332 algo=8
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+www.sub2.example.net. IN A
+SECTION ANSWER
+www.sub2.example.net. IN A     10.20.30.42
+www.sub2.example.net.  3600    IN      RRSIG   A 8 4 3600 20070926134150 20070829134150 29332 sub2.example.net. FOY6YxNoFyrSkBtWV7HcECmORTMedRWHdGk7Rm04icT8Bw0dWfzVaIpAkBY6FXx8UvqN7McN4IJI5dAVXptfekO+Yvy2PwkjehRUXvQK64XH5UM5pVbX5g8E4pnOrLa/jzPB7srzMpyWVCpt81lPoFpdfXUMm7434ifkTYhpAll7y5NAocFiT3F+XGe06qMIr51WxoFfegIGohMFhkTDUdLWrdV10128W+NzPdwoYtiigtCObKxTtyj3gK+mxqXvX4X4F2YIGQ+mx62ovdUilnLYZm/WC/ZQkdxeOZjeCTxvSpGGG+wtu1QufgIJ+BpAZAOxREOYZkhR29AG0np4EA==
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR SERVFAIL
+SECTION QUESTION
+sub2.example.net. IN DNSKEY
+SECTION ANSWER
+; sub2.example.net.       IN      DNSKEY  257 3 8 AwEAAb4WMOTBLTFvmBra5m6SK4VfViOzmvyUAU0qv861ZQXeEFvwlndqNU9rwRsMxrSWAYs5nHErKDn49usC/HyxxW1477iGFHhfgL4mjNreJm9zft2QFB1VLbRbEPYdDMLCn4co0qnG7/KG8W2i8Pym1L7f+aREwbLo+/716AS2PbaKMhfWLKLiq5wnBcUClQMNzCiwhqxDJp1oePqfkVdeUgXOtgi0dYRIKyQFhJ5VWJ22npoi/Gif0XLCADAlAwRLKc8o/yJkCxskzgpHpw5Cki1lclg0aq4ssOuPRQ+ne6IHYCz9D2mwzulblhLFamKdq7aHzNt4NlyxhpANVFiKLD8= ;{id = 29332 (ksk), size = 2048b}
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA NOERROR
+SECTION QUESTION
+sub2.example.net. IN DS
+SECTION ANSWER
+sub2.example.net.       3600    IN      DS      29332 8 2 d53e615d9d736b0f2a0097f1d5fa51c84320610f94ecbd7197e7de5f44f02d72
+sub2.example.net.      3600    IN      RRSIG   DS 8 3 3600 20070926134150 20070829134150 1444 example.net. dYLYs1uMxJm5+MB6L1+uStE5S1YtyYR0JF+1pPoTptc/H1hYqMxK7pVQPtIGvq8j8wNyC7jOzALfEXgwRKiSdR1l1GQ5HIxWkhUmkpLcecwJOjemee4nXaifOFa5bdbdYpuDwTiIzx+PvanlaVjEPy0i1IukanDi6jojfyWcgLA=
+ENTRY_END
+RANGE_END
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.example.com. IN A
+ENTRY_END
+
+; The DNSKEY lookup for the key prime is a failure.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ede=9
+REPLY QR RD RA DO SERVFAIL
+SECTION QUESTION
+www.example.com. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 20 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.sub1.example.net. IN A
+ENTRY_END
+
+; The DS lookup is a failure.
+STEP 30 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ede=23
+REPLY QR RD RA DO SERVFAIL
+SECTION QUESTION
+www.sub1.example.net. IN A
+SECTION ANSWER
+ENTRY_END
+
+STEP 40 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.sub2.example.net. IN A
+ENTRY_END
+
+; The DNSKEY lookup is a failure.
+STEP 50 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all ede=9
+REPLY QR RD RA DO SERVFAIL
+SECTION QUESTION
+www.sub2.example.net. IN A
+SECTION ANSWER
+ENTRY_END
+
+SCENARIO_END
index 39ae58eae721d7615b856231a594b7ca415bb983..59226abccd44550f659d2c3dd23ddcdf40608d38 100644 (file)
@@ -72,7 +72,8 @@
 /* forward decl for cache response and normal super inform calls of a DS */
 static void process_ds_response(struct module_qstate* qstate, 
        struct val_qstate* vq, int id, int rcode, struct dns_msg* msg, 
-       struct query_info* qinfo, struct sock_list* origin, int* suspend);
+       struct query_info* qinfo, struct sock_list* origin, int* suspend,
+       struct module_qstate* sub_qstate);
 
 
 /* Updates the suplied EDE (RFC8914) code selectively so we don't lose
@@ -2066,7 +2067,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
                        verbose(VERB_ALGO, "Process suspended sub DS response");
                        msg = vq->sub_ds_msg;
                        process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
-                               msg, &msg->qinfo, NULL, &suspend);
+                               msg, &msg->qinfo, NULL, &suspend, NULL);
                        if(suspend) {
                                /* we'll come back here later to continue */
                                if(!validate_suspend_setup_timer(qstate, vq,
@@ -2082,7 +2083,7 @@ processFindKey(struct module_qstate* qstate, struct val_qstate* vq, int id)
                        vq->key_entry->name)) ) {
                        verbose(VERB_ALGO, "Process cached DS response");
                        process_ds_response(qstate, vq, id, LDNS_RCODE_NOERROR,
-                               msg, &msg->qinfo, NULL, &suspend);
+                               msg, &msg->qinfo, NULL, &suspend, NULL);
                        if(suspend) {
                                /* we'll come back here later to continue */
                                if(!validate_suspend_setup_timer(qstate, vq,
@@ -2664,6 +2665,8 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
  * @param ta: trust anchor.
  * @param qstate: qstate that needs key.
  * @param id: module id.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ *     the trust anchor data, it contains error information for the answer.
  * @return new key entry or NULL on allocation failure.
  *     The key entry will either contain a validated DNSKEY rrset, or
  *     represent a Null key (query failed, but validation did not), or a
@@ -2671,7 +2674,8 @@ val_operate(struct module_qstate* qstate, enum module_ev event, int id,
  */
 static struct key_entry_key*
 primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset, 
-       struct trust_anchor* ta, struct module_qstate* qstate, int id)
+       struct trust_anchor* ta, struct module_qstate* qstate, int id,
+       struct module_qstate* sub_qstate)
 {
        struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
        struct key_entry_key* kkey = NULL;
@@ -2681,11 +2685,18 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
        int downprot = qstate->env->cfg->harden_algo_downgrade;
 
        if(!dnskey_rrset) {
+               char* err = errinf_to_str_misc(sub_qstate);
+               char reason[1024];
                log_nametypeclass(VERB_OPS, "failed to prime trust anchor -- "
                        "could not fetch DNSKEY rrset", 
                        ta->name, LDNS_RR_TYPE_DNSKEY, ta->dclass);
                reason_bogus = LDNS_EDE_DNSKEY_MISSING;
-               reason = "no DNSKEY rrset";
+               if(!err) {
+                       snprintf(reason, sizeof(reason), "no DNSKEY rrset");
+               } else {
+                       snprintf(reason, sizeof(reason), "no DNSKEY rrset "
+                               "[%s]", err);
+               }
                if(qstate->env->cfg->harden_dnssec_stripped) {
                        errinf_ede(qstate, reason, reason_bogus);
                        kkey = key_entry_create_bad(qstate->region, ta->name,
@@ -2760,6 +2771,9 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
  *     DS response indicated an end to secure space, is_good if the DS
  *     validated. It returns ke=NULL if the DS response indicated that the
  *     request wasn't a delegation point.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ *     the trust anchor data, it contains error information for the answer.
+ *     Can be NULL.
  * @return
  *     0 on success,
  *     1 on servfail error (malloc failure),
@@ -2768,7 +2782,7 @@ primeResponseToKE(struct ub_packed_rrset_key* dnskey_rrset,
 static int
 ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
         int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
-       struct key_entry_key** ke)
+       struct key_entry_key** ke, struct module_qstate* sub_qstate)
 {
        struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
        char* reason = NULL;
@@ -2783,6 +2797,11 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
                verbose(VERB_DETAIL, "DS response was error, thus bogus");
                errinf(qstate, rc);
                reason = "no DS";
+               if(sub_qstate) {
+                       errinf(qstate, "[");
+                       errinf(qstate, errinf_to_str_misc(sub_qstate));
+                       errinf(qstate, "]");
+               }
                reason_bogus = LDNS_EDE_NETWORK_ERROR;
                errinf_ede(qstate, reason, reason_bogus);
                goto return_bogus;
@@ -3008,11 +3027,15 @@ return_bogus:
  * @param origin: the origin of msg.
  * @param suspend: returned true if the task takes too long and needs to
  *     suspend to continue the effort later.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ *     the trust anchor data, it contains error information for the answer.
+ *     Can be NULL.
  */
 static void
 process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
        int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
-       struct sock_list* origin, int* suspend)
+       struct sock_list* origin, int* suspend,
+       struct module_qstate* sub_qstate)
 {
        struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
        struct key_entry_key* dske = NULL;
@@ -3020,7 +3043,8 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
        int ret;
        *suspend = 0;
        vq->empty_DS_name = NULL;
-       ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske);
+       ret = ds_response_to_ke(qstate, vq, id, rcode, msg, qinfo, &dske,
+               sub_qstate);
        if(ret != 0) {
                switch(ret) {
                case 1:
@@ -3096,11 +3120,13 @@ process_ds_response(struct module_qstate* qstate, struct val_qstate* vq,
  * @param msg: result message (if rcode is OK).
  * @param qinfo: from the sub query state, query info.
  * @param origin: the origin of msg.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ *     the trust anchor data, it contains error information for the answer.
  */
 static void
 process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
        int id, int rcode, struct dns_msg* msg, struct query_info* qinfo,
-       struct sock_list* origin)
+       struct sock_list* origin, struct module_qstate* sub_qstate)
 {
        struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
        struct key_entry_key* old = vq->key_entry;
@@ -3113,6 +3139,8 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
                dnskey = reply_find_answer_rrset(qinfo, msg->rep);
 
        if(dnskey == NULL) {
+               char* err;
+               char reason[1024];
                /* bad response */
                verbose(VERB_DETAIL, "Missing DNSKEY RRset in response to "
                        "DNSKEY query.");
@@ -3124,7 +3152,13 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
                        vq->restart_count++;
                        return;
                }
-               reason = "No DNSKEY record";
+               err = errinf_to_str_misc(sub_qstate);
+               if(!err) {
+                       snprintf(reason, sizeof(reason), "No DNSKEY record");
+               } else {
+                       snprintf(reason, sizeof(reason), "No DNSKEY record "
+                               "[%s]", err);
+               }
                reason_bogus = LDNS_EDE_DNSKEY_MISSING;
                vq->key_entry = key_entry_create_bad(qstate->region,
                        qinfo->qname, qinfo->qname_len, qinfo->qclass,
@@ -3198,10 +3232,13 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq,
  * @param rcode: rcode result value.
  * @param msg: result message (if rcode is OK).
  * @param origin: the origin of msg.
+ * @param sub_qstate: the sub query state, that is the lookup that fetched
+ *     the trust anchor data, it contains error information for the answer.
  */
 static void
 process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
-       int id, int rcode, struct dns_msg* msg, struct sock_list* origin)
+       int id, int rcode, struct dns_msg* msg, struct sock_list* origin,
+       struct module_qstate* sub_qstate)
 {
        struct val_env* ve = (struct val_env*)qstate->env->modinfo[id];
        struct ub_packed_rrset_key* dnskey_rrset = NULL;
@@ -3233,7 +3270,8 @@ process_prime_response(struct module_qstate* qstate, struct val_qstate* vq,
                        return;
                }
        }
-       vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id);
+       vq->key_entry = primeResponseToKE(dnskey_rrset, ta, qstate, id,
+               sub_qstate);
        lock_basic_unlock(&ta->lock);
        if(vq->key_entry) {
                if(key_entry_isbad(vq->key_entry) 
@@ -3284,14 +3322,14 @@ val_inform_super(struct module_qstate* qstate, int id,
        if(vq->wait_prime_ta) {
                vq->wait_prime_ta = 0;
                process_prime_response(super, vq, id, qstate->return_rcode,
-                       qstate->return_msg, qstate->reply_origin);
+                       qstate->return_msg, qstate->reply_origin, qstate);
                return;
        }
        if(qstate->qinfo.qtype == LDNS_RR_TYPE_DS) {
                int suspend;
                process_ds_response(super, vq, id, qstate->return_rcode,
                        qstate->return_msg, &qstate->qinfo,
-                       qstate->reply_origin, &suspend);
+                       qstate->reply_origin, &suspend, qstate);
                /* If NSEC3 was needed during validation, NULL the NSEC3 cache;
                 * it will be re-initiated if needed later on.
                 * Validation (and the cache table) are happening/allocated in
@@ -3312,7 +3350,7 @@ val_inform_super(struct module_qstate* qstate, int id,
        } else if(qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY) {
                process_dnskey_response(super, vq, id, qstate->return_rcode,
                        qstate->return_msg, &qstate->qinfo,
-                       qstate->reply_origin);
+                       qstate->reply_origin, qstate);
                return;
        }
        log_err("internal error in validator: no inform_supers possible");