diff --git a/doc/Changelog b/doc/Changelog index dddf7b481..ce478670a 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -2,6 +2,9 @@ - Fix of message parse bug where (specifically) an NSEC and RRSIG in the wrong order would be parsed, but put wrongly into internal structures so that later validation would fail. + - Extreme lenience for wrongly truncated replies where a positive + reply has an NS in the authority but no signatures. They are + turned into minimal responses with only the (secure) answer. 17 June 2009: Wouter - CREDITS entry for cz.nic, sponsoring a 'summer of code' that was diff --git a/testdata/val_pos_truncns.rpl b/testdata/val_pos_truncns.rpl new file mode 100644 index 000000000..63b7fd0fd --- /dev/null +++ b/testdata/val_pos_truncns.rpl @@ -0,0 +1,148 @@ +; config options +; The island of trust is at example.com +server: + trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b" + val-override-date: "20070916134226" + target-fetch-policy: "0 0 0 0 0" + +stub-zone: + name: "." + stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. +CONFIG_END + +SCENARIO_BEGIN Test validator with badly truncated positive response + +; 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 qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION AUTHORITY +com. 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 qtype qname +ADJUST copy_id +REPLY QR NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION AUTHORITY +example.com. IN NS ns.example.com. +SECTION ADDITIONAL +ns.example.com. IN A 1.2.3.4 +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 + +; 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 + +; 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 +www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} +SECTION AUTHORITY +example.com. IN NS ns.example.com. + +; Truncated, no signature for NS record. +;;;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 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854} +ENTRY_END +RANGE_END + +STEP 1 QUERY +ENTRY_BEGIN +REPLY RD DO +SECTION QUESTION +www.example.com. IN A +ENTRY_END + +; recursion happens here. +STEP 10 CHECK_ANSWER +ENTRY_BEGIN +MATCH all +REPLY QR RD RA AD NOERROR +SECTION QUESTION +www.example.com. IN A +SECTION ANSWER +www.example.com. IN A 10.20.30.40 +www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} +SECTION AUTHORITY +SECTION ADDITIONAL +ENTRY_END + +SCENARIO_END diff --git a/validator/validator.c b/validator/validator.c index f613f7775..098cd3a67 100644 --- a/validator/validator.c +++ b/validator/validator.c @@ -478,6 +478,36 @@ validate_msg_signatures(struct module_env* env, struct val_env* ve, return 1; } +/** + * Detect wrong truncated response, by a bad recursor out there. + * The positive response has a mangled authority section. + * Remove that authority section. + * @param rep: reply + * @return true if a wrongly truncated response. + */ +static int +detect_wrongly_truncated(struct reply_info* rep) +{ + size_t i; + /* no additional, only NS in authority, and it is bogus */ + if(rep->ar_numrrsets != 0 || rep->ns_numrrsets != 1 || + rep->an_numrrsets == 0) + return 0; + if(ntohs(rep->rrsets[ rep->an_numrrsets ]->rk.type) != LDNS_RR_TYPE_NS) + return 0; + if(((struct packed_rrset_data*)rep->rrsets[ rep->an_numrrsets ] + ->entry.data)->security != sec_status_bogus) + return 0; + /* answer section is present and secure */ + for(i=0; ian_numrrsets; i++) { + if(((struct packed_rrset_data*)rep->rrsets[ i ] + ->entry.data)->security != sec_status_secure) + return 0; + } + return 1; +} + + /** * Given a "positive" response -- a response that contains an answer to the * question, and no CNAME chain, validate this response. @@ -1449,17 +1479,31 @@ processValidate(struct module_qstate* qstate, struct val_qstate* vq, vq->chase_reply->security = sec_status_bogus; return 1; } + subtype = val_classify_response(qstate->query_flags, &qstate->qinfo, + &vq->qchase, vq->orig_msg->rep, vq->rrset_skip); /* check signatures in the message; * answer and authority must be valid, additional is only checked. */ if(!validate_msg_signatures(qstate->env, ve, &vq->qchase, vq->chase_reply, vq->key_entry)) { - verbose(VERB_DETAIL, "Validate: message contains bad rrsets"); - return 1; + /* workaround bad recursor out there that truncates (even + * with EDNS4k) to 512 by removing RRSIG from auth section + * for positive replies*/ + if(subtype == VAL_CLASS_POSITIVE && + detect_wrongly_truncated(vq->orig_msg->rep)) { + /* truncate the message some more */ + vq->orig_msg->rep->ns_numrrsets = 0; + vq->orig_msg->rep->rrset_count--; + vq->chase_reply->ns_numrrsets = 0; + vq->chase_reply->rrset_count--; + } + else { + verbose(VERB_DETAIL, "Validate: message contains " + "bad rrsets"); + return 1; + } } - subtype = val_classify_response(qstate->query_flags, &qstate->qinfo, - &vq->qchase, vq->orig_msg->rep, vq->rrset_skip); switch(subtype) { case VAL_CLASS_POSITIVE: verbose(VERB_ALGO, "Validating a positive response");