2 // dnssec_v2_retrieval.c
5 // Copyright (c) 2020 Apple Inc. All rights reserved.
8 #include "mDNSEmbeddedAPI.h"
9 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
10 #include <string.h> // for strerror
11 #include <errno.h> // for errno
12 #include "DNSCommon.h"
13 #include "dnssec_v2.h"
14 #include "dnssec_v2_helper.h"
15 #include "dnssec_v2_retrieval.h"
16 #include "dnssec_v2_client.h"
19 //======================================================================================================================
20 // local functions prototypes
21 //======================================================================================================================
23 mDNSlocal response_type_t
24 determine_response_type(mDNSu16 rr_type
, const mDNSu8
* const _Nullable rdata
, const mDNSu16 question_type
);
27 domain_name_end_with(const mDNSu8
* const _Nonnull longer
, const mDNSu8
* const _Nonnull shorter
);
29 mDNSlocal
const mDNSu8
* _Nullable
30 get_parent_zone_name(const list_t
* const _Nonnull zones
, originals_with_rrsig_t
* const _Nonnull original
);
33 nsec_nsec3_contains_rrsigs_with_same_signer(const list_t
* const nsec_nsec3_list
, mDNSu16 type
);
35 //======================================================================================================================
37 //======================================================================================================================
39 //======================================================================================================================
40 // initialize_dnssec_status_t
41 //======================================================================================================================
44 initialize_dnssec_status_t(dnssec_status_t
* const _Nonnull status
, const domainname
* const _Nonnull qname
,
45 const mDNSu16 qtype
, const mDNSu32 flags
, void * const _Nonnull context
) {
47 // Query ends with ".local." and query for RRSIG or ANY type cannot be validated by DNSSEC even if the user sets the
48 // kDNSServiceFlagsEnableDNSSEC flag.
49 mDNSBool enable_dnssec
= FLAGS_CONTAIN_DNSOK_BIT(flags
) && is_eligible_for_dnssec(qname
, qtype
);
52 status
->enable_dnssec
= mDNStrue
;
53 status
->tried_dnssec_but_unsigned
= mDNSfalse
;
54 status
->context
= context
;
56 // if the question does not enable DNSSEC, only status->enable_dnssec is meaningful.
57 status
->enable_dnssec
= mDNSfalse
;
58 status
->tried_dnssec_but_unsigned
= mDNSfalse
;
59 status
->context
= mDNSNULL
;
62 return mStatus_NoError
;
65 //======================================================================================================================
66 // uninitialize_dnssec_status_t
67 //======================================================================================================================
70 uninitialize_dnssec_status_t(dnssec_status_t
* const _Nonnull __unused status
) {
71 status
->enable_dnssec
= mDNSfalse
;
72 status
->tried_dnssec_but_unsigned
= mDNSfalse
;
73 status
->context
= mDNSNULL
;
74 return mStatus_NoError
;
77 #pragma mark - dnssec_context_t functions
81 #pragma mark create_dnssec_context_t
83 create_dnssec_context_t(
84 QueryRecordClientRequest
* const _Nullable request
,
85 const mDNSu32 request_id
,
86 const domainname
* const _Nonnull question_name
,
87 const mDNSu16 question_type
,
88 const mDNSu16 question_class
,
89 const mDNSInterfaceID _Nullable interface_id
,
90 const mDNSs32 service_id
,
92 const mDNSBool append_search_domains
,
94 const mDNSu8
* _Nullable uuid
,
96 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
97 const audit_token_t
* _Nullable peer_audit_token_ptr
,
98 const audit_token_t
* _Nullable delegate_audit_token_ptr
,
100 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
101 const mDNSu8
* _Nullable resolver_uuid
,
102 mDNSBool need_encryption
,
103 const mdns_dns_service_id_t custom_id
,
105 const QueryRecordResultHandler _Nonnull result_handler
,
106 void * const _Nullable result_context
,
107 dnssec_context_t
* const _Nullable primary_dnssec_context
,
108 dnssec_context_t
* _Nullable
* const _Nonnull out_dnssec_context
) {
110 mStatus error
= mStatus_NoError
;
111 dnssec_context_t
* context
= mDNSNULL
;
112 mDNSBool context_created
= mDNSfalse
;
113 original_request_parameters_t
*parameters
;
115 context
= calloc(1, sizeof(dnssec_context_t
)); // must use calloc here to set context to all 0s
116 require_action(context
!= mDNSNULL
, exit
, error
= mStatus_NoMemoryErr
; log_debug("calloc failed; error_description='%s'", strerror(errno
)));
117 context_created
= mDNStrue
;
119 context
->me
= request
;
121 list_init(&context
->zone_chain
, sizeof(dnssec_zone_t
));
123 // initialize original request fields
124 original_t
* const original
= &context
->original
;
125 original
->original_result_with_rrsig
.type
= unknown_response
;
127 parameters
= &original
->original_parameters
;
128 parameters
->request_id
= request_id
;
129 memcpy(parameters
->question_name
.c
, question_name
->c
, DOMAIN_NAME_LENGTH(question_name
->c
));
130 parameters
->question_name_hash
= DomainNameHashValue(¶meters
->question_name
);
131 parameters
->question_type
= question_type
;
132 parameters
->question_class
= question_class
;
133 parameters
->interface_id
= interface_id
;
134 parameters
->service_id
= service_id
;
135 parameters
->flags
= flags
;
136 parameters
->append_search_domains
= append_search_domains
;
137 parameters
->pid
= pid
;
138 if (uuid
!= mDNSNULL
) {
139 uuid_copy(parameters
->uuid
, uuid
);
141 uuid_clear(parameters
->uuid
);
143 parameters
->uid
= uid
;
144 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
145 if (peer_audit_token_ptr
!= mDNSNULL
) {
146 parameters
->peer_audit_token
= *peer_audit_token_ptr
;
147 parameters
->has_peer_audit_token
= mDNStrue
;
149 parameters
->has_peer_audit_token
= mDNSfalse
;
151 if (delegate_audit_token_ptr
!= mDNSNULL
) {
152 parameters
->delegate_audit_token
= *delegate_audit_token_ptr
;
153 parameters
->has_delegate_audit_token
= mDNStrue
;
155 parameters
->has_delegate_audit_token
= mDNSfalse
;
158 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
159 if (resolver_uuid
!= mDNSNULL
) {
160 uuid_copy(parameters
->resolver_uuid
, resolver_uuid
);
162 uuid_clear(parameters
->resolver_uuid
);
164 parameters
->need_encryption
= need_encryption
;
165 parameters
->custom_id
= custom_id
;
167 parameters
->user_handler
= result_handler
;
168 parameters
->user_context
= result_context
;
170 original
->original_trust_anchor
= mDNSNULL
;
171 original
->last_time_add
= INT_MIN
;
172 original
->last_time_rmv
= INT_MIN
;
174 // initialize returned_answers_t
175 initialize_returned_answers_t(&context
->returned_answers
, dnssec_indeterminate
, kDNSServiceErr_Invalid
);
177 // initialize denial of existence fields
178 context
->denial_of_existence_records
= mDNSNULL
;
180 context
->primary_dnssec_context
= primary_dnssec_context
;
181 context
->subtask_dnssec_context
= mDNSNULL
;
183 *out_dnssec_context
= context
;
186 if (error
!= mStatus_NoError
&& context_created
) free(context
);
190 #pragma mark print_dnssec_context_t
192 print_dnssec_context_t(const dnssec_context_t
* const _Nonnull context
) {
193 mDNSu8 num_of_tabs
= 0;
196 log_debug(TAB_STR
"DNSSEC Context:", TAB_PARAM(num_of_tabs
));
197 print_original_request_parameters_t(&context
->original
.original_parameters
, num_of_tabs
+ 1);
198 log_debug(TAB_STR
"--------------------------------------------------", TAB_PARAM(num_of_tabs
));
200 log_debug(TAB_STR
"Original Response:", TAB_PARAM(num_of_tabs
));
201 print_originals_with_rrsig_t(&context
->original
.original_result_with_rrsig
, num_of_tabs
+ 1);
202 log_debug(TAB_STR
"--------------------------------------------------", TAB_PARAM(num_of_tabs
));
204 log_debug(TAB_STR
"Zones:", TAB_PARAM(num_of_tabs
));
205 for (list_node_t
*node
= list_get_first(&context
->zone_chain
);
206 !list_has_ended(&context
->zone_chain
, node
);
207 node
= list_next(node
)) {
208 dnssec_zone_t
*zone
= (dnssec_zone_t
*)node
->data
;
209 print_dnssec_zone_t(zone
, num_of_tabs
+ 1);
212 log_debug(TAB_STR
"Returned Response:", TAB_PARAM(num_of_tabs
));
213 print_returned_answers_t(&context
->returned_answers
, num_of_tabs
+ 1);
214 log_debug(TAB_STR
"--------------------------------------------------", TAB_PARAM(num_of_tabs
));
218 #pragma mark destroy_dnssec_context_t
220 destroy_dnssec_context_t(dnssec_context_t
* const _Nonnull context
) {
221 list_uninit(&context
->zone_chain
);
222 uninitialize_returned_answers_t(&context
->returned_answers
);
226 #pragma mark - add_no_error_records
229 is_response_for_original_request(
230 const original_t
* const _Nonnull original
,
231 const DNSQuestion
* const _Nonnull question
);
233 mDNSexport dnssec_retrieval_result_t
234 add_no_error_records(
235 mDNS
*const _Nonnull m
,
236 DNSQuestion
* _Nonnull question
,
237 const ResourceRecord
* const _Nonnull answer
,
238 const QC_result add_record
,
239 const DNSServiceErrorType dns_result_error
,
240 dnssec_context_t
* const _Nonnull dnssec_context
) {
242 dnssec_retrieval_result_t result
;
244 dnssec_zone_t
* const zone
= find_dnssec_zone_t(&dnssec_context
->zone_chain
, question
->qname
.c
);
246 if (is_response_for_original_request(&dnssec_context
->original
, question
)) {
247 // original response requested by user
248 result
= update_original_from_cache_for_no_error_response(m
, question
, answer
, add_record
, dns_result_error
,
250 require_quiet(result
== dnssec_retrieval_no_error
, exit
);
253 // it is possible that user queries for A record for apple.com, and there is also a zone called "apple.com"
254 if (zone
!= mDNSNULL
) {
255 // DS/DNSKEY response
256 result
= update_dnssec_zone_t_from_cache_for_no_error_response(m
, question
, answer
, add_record
, zone
);
257 require_quiet(result
== dnssec_retrieval_no_error
, exit
);
260 result
= dnssec_retrieval_no_error
;
265 #pragma mark is_response_for_original_request
267 is_response_for_original_request(
268 const original_t
* const _Nonnull original
,
269 const DNSQuestion
* const _Nonnull question
) {
271 mDNSBool is_original_request
= mDNSfalse
;
272 const original_request_parameters_t
* const parameters
= &original
->original_parameters
;
274 if (parameters
->question_name_hash
!= question
->qnamehash
) {
278 if (parameters
->question_type
!= question
->qtype
) {
282 if (parameters
->question_class
!= question
->qclass
) {
286 if (!DOMAIN_NAME_EQUALS(parameters
->question_name
.c
, question
->qname
.c
)) {
290 is_original_request
= mDNStrue
;
292 return is_original_request
;
295 #pragma mark - add_denial_of_existence_records
296 mDNSexport dnssec_retrieval_result_t
297 add_denial_of_existence_records(
298 const mDNS
*const _Nonnull m
,
299 const DNSQuestion
* _Nonnull question
,
300 ResourceRecord
* const _Nonnull answer
,
301 const QC_result add_record
,
302 const DNSServiceErrorType dns_result_error
,
303 dnssec_context_t
* const _Nonnull dnssec_context
) {
305 dnssec_retrieval_result_t result
;
307 if (is_response_for_original_request(&dnssec_context
->original
, question
)) {
308 result
= update_original_from_cache_for_denial_of_existence_response(m
, question
, answer
, add_record
, dns_result_error
, dnssec_context
);
309 require_quiet(result
== dnssec_retrieval_no_error
, exit
);
311 result
= dnssec_retrieval_non_dnskey_ds_record_for_zone
;
319 //======================================================================================================================
320 // fetch_necessary_dnssec_records
321 //======================================================================================================================
323 mDNSexport dnssec_retrieval_result_t
324 fetch_necessary_dnssec_records(dnssec_context_t
* const _Nonnull context
, mDNSBool anchor_reached
) {
325 // if we reach here, it means we need at least 1 zone node to finish the validation process
326 // or the current top parent node has a trust anchor that does not pass the validation
327 mStatus error
= mStatus_NoError
;
328 dnssec_retrieval_result_t retrieval_result
= dnssec_retrieval_no_error
;
329 list_t
* zones
= &context
->zone_chain
;
330 dnssec_zone_t
* zone
= mDNSNULL
;
331 original_request_parameters_t
* params
= &context
->original
.original_parameters
;
332 const mDNSu8
* parent_zone_name
;
333 const mDNSu32 request_id
= context
->original
.original_parameters
.request_id
;
335 zone
= list_empty(zones
) ? mDNSNULL
: (dnssec_zone_t
*)list_get_last(zones
)->data
;
337 mDNSBool is_root
= (zone
!= mDNSNULL
) ? (is_root_domain(zone
->domain_name
.c
)) : mDNSfalse
;
338 require_action_quiet(!is_root
, exit
, retrieval_result
= dnssec_retrieval_waiting_for_records
);
340 if (zone
== mDNSNULL
|| zone
->trust_anchor
== mDNSNULL
) {
341 // normal case, get new records from the "Signer Name"
342 parent_zone_name
= get_parent_zone_name(zones
, &context
->original
.original_result_with_rrsig
);
343 require_action_quiet(parent_zone_name
!= mDNSNULL
, exit
, retrieval_result
= dnssec_retrieval_waiting_for_records
);
345 require_action(list_count_node(zones
) < MAX_ZONES_ALLOWED
, exit
, retrieval_result
= dnssec_retrieval_too_many_zones
);
347 error
= list_append_uinitialized(zones
, sizeof(dnssec_zone_t
), (void **)&zone
);
348 require_action(error
== mStatus_NoError
, exit
, retrieval_result
= dnssec_retrieval_record_not_added
;
349 log_debug("list_add_front_uinitialized failed; error_description='%s'", mStatusDescription(error
)));
351 initialize_dnssec_zone_t(zone
, parent_zone_name
);
353 if (trust_anchor_contains_dnskey(zone
->trust_anchor
)) {
354 retrieval_result
= dnssec_retrieval_validate_again
;
355 zone
->dnskey_request_started
= mDNSfalse
;
356 zone
->ds_request_started
= mDNSfalse
;
357 } else if (trust_anchor_contains_ds(zone
->trust_anchor
)) {
358 zone
->dnskey_request_started
= mDNStrue
;
359 zone
->ds_request_started
= mDNSfalse
;
361 zone
->dnskey_request_started
= mDNStrue
;
362 zone
->ds_request_started
= mDNStrue
;
365 if (zone
->dnskey_request_started
) {
366 error
= QueryRecordOpStartForClientRequest(
367 &zone
->dnskey_request
.op
, params
->request_id
, (const domainname
*)parent_zone_name
, kDNSType_DNSKEY
,
368 params
->question_class
, params
->interface_id
, params
->service_id
, params
->flags
, params
->append_search_domains
,
369 params
->pid
, params
->uuid
, params
->uid
,
370 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
371 params
->has_peer_audit_token
? ¶ms
->peer_audit_token
: mDNSNULL
,
372 params
->has_delegate_audit_token
? ¶ms
->delegate_audit_token
: mDNSNULL
,
374 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
375 params
->resolver_uuid
, params
->need_encryption
, params
->custom_id
,
377 query_record_result_reply_with_dnssec
, context
);
378 require_action(error
== mStatus_NoError
, exit
, retrieval_result
= dnssec_retrieval_query_failed
;
379 log_debug("QueryRecordOpStart failed; error_description='%s'", mStatusDescription(error
)));
382 if (zone
->ds_request_started
) {
383 error
= QueryRecordOpStartForClientRequest(
384 &zone
->ds_request
.op
, params
->request_id
, (const domainname
*)parent_zone_name
, kDNSType_DS
,
385 params
->question_class
, params
->interface_id
, params
->service_id
, params
->flags
, params
->append_search_domains
,
386 params
->pid
, params
->uuid
, params
->uid
,
387 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
388 params
->has_peer_audit_token
? ¶ms
->peer_audit_token
: mDNSNULL
,
389 params
->has_delegate_audit_token
? ¶ms
->delegate_audit_token
: mDNSNULL
,
391 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
392 params
->resolver_uuid
, params
->need_encryption
, params
->custom_id
,
394 query_record_result_reply_with_dnssec
, context
);
395 require_action(error
== mStatus_NoError
, exit
, retrieval_result
= dnssec_retrieval_query_failed
;
396 log_debug("QueryRecordOpStart failed; error_description='%s'", mStatusDescription(error
)));
399 // special case where the trust anchor does not verify the records
400 require_action_quiet(anchor_reached
, exit
,
401 retrieval_result
= dnssec_retrieval_waiting_for_records
; log_default("[R%u] still waiting for the response from child zones", request_id
));
403 zone
->trust_anchor
= mDNSNULL
;
405 if (!zone
->dnskey_request_started
) {
406 error
= QueryRecordOpStartForClientRequest(
407 &zone
->dnskey_request
.op
, params
->request_id
, &zone
->domain_name
, kDNSType_DNSKEY
,
408 params
->question_class
, params
->interface_id
, params
->service_id
, params
->flags
, params
->append_search_domains
,
409 params
->pid
, params
->uuid
, params
->uid
,
410 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
411 params
->has_peer_audit_token
? ¶ms
->peer_audit_token
: mDNSNULL
,
412 params
->has_delegate_audit_token
? ¶ms
->peer_audit_token
: mDNSNULL
,
414 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
415 params
->resolver_uuid
, params
->need_encryption
, params
->custom_id
,
417 query_record_result_reply_with_dnssec
, context
);
418 require_action(error
== mStatus_NoError
, exit
, retrieval_result
= dnssec_retrieval_query_failed
;
419 log_debug("QueryRecordOpStart failed; error_description='%s'", mStatusDescription(error
)));
420 zone
->dnskey_request_started
= mDNStrue
;
423 if (!zone
->ds_request_started
&& !is_root_domain(zone
->domain_name
.c
)) {
424 error
= QueryRecordOpStartForClientRequest(
425 &zone
->ds_request
.op
, params
->request_id
, &zone
->domain_name
, kDNSType_DS
,
426 params
->question_class
, params
->interface_id
, params
->service_id
, params
->flags
, params
->append_search_domains
,
427 params
->pid
, params
->uuid
, params
->uid
,
428 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
429 params
->has_peer_audit_token
? ¶ms
->peer_audit_token
: mDNSNULL
,
430 params
->has_delegate_audit_token
? ¶ms
->delegate_audit_token
: mDNSNULL
,
432 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
433 params
->resolver_uuid
, params
->need_encryption
, params
->custom_id
,
435 query_record_result_reply_with_dnssec
, context
);
436 require_action(error
== mStatus_NoError
, exit
, retrieval_result
= dnssec_retrieval_query_failed
;
437 log_debug("QueryRecordOpStart failed; error_description='%s'", mStatusDescription(error
)));
438 zone
->ds_request_started
= mDNStrue
;
443 if (retrieval_result
< 0) {
444 if (zone
!= mDNSNULL
) {
445 if (zone
->dnskey_request_started
|| zone
->ds_request_started
) {
446 // TODO: return correct error code to user and clean the dnssec related structure gracefully
448 uninitialize_dnssec_zone_t(zone
);
449 list_delete_node_with_data_ptr(zones
, (void *)zone
);
453 return retrieval_result
;
456 //======================================================================================================================
457 // find_dnssec_zone_t
458 //======================================================================================================================
460 mDNSexport dnssec_zone_t
* _Nullable
461 find_dnssec_zone_t(const list_t
* const _Nonnull zones
, const mDNSu8
* const _Nonnull name
) {
462 for (list_node_t
*ptr
= list_get_first(zones
); !list_has_ended(zones
, ptr
); ptr
= list_next(ptr
)) {
463 dnssec_zone_t
*zone
= (dnssec_zone_t
*)ptr
->data
;
464 if (DOMAIN_NAME_EQUALS(&zone
->domain_name
, name
)) {
472 //======================================================================================================================
473 // add_to_cname_with_rrsig_t
474 //======================================================================================================================
477 add_to_cname_with_rrsig_t(cnames_with_rrsig_t
* const _Nonnull cnames_with_rrisg
, ResourceRecord
* const _Nonnull rr
) {
478 mStatus error
= mStatus_NoError
;
479 list_t
* cname_records
= &cnames_with_rrisg
->cname_records
;
480 list_t
* rrsig_records
= &cnames_with_rrisg
->rrsig_records
;
481 dnssec_cname_t
*cname
= mDNSNULL
;
482 dnssec_rrsig_t
*rrsig
= mDNSNULL
;
484 if (rr
->rrtype
== kDNSType_CNAME
) {
485 error
= list_append_uinitialized(cname_records
, sizeof(dnssec_cname_t
), (void **)&cname
);
486 require_action(error
== mStatus_NoError
, exit
, log_debug("list_append_uinitialized failed; error_description='%s'", mStatusDescription(error
)));
488 initialize_dnssec_cname_t(cname
, rr
);
490 mDNSBool is_rrsig_valid
= mDNSfalse
;
492 verify(rr
->rrtype
== kDNSType_RRSIG
);
493 error
= list_append_uinitialized(&cnames_with_rrisg
->rrsig_records
, sizeof(dnssec_rrsig_t
), (void **)&rrsig
);
494 require_action(error
== mStatus_NoError
, exit
, log_debug("list_append_uinitialized failed; error_description='%s'", mStatusDescription(error
)));
496 is_rrsig_valid
= initialize_dnssec_rrsig_t(rrsig
, rr
);
497 require_action_quiet(is_rrsig_valid
, exit
, error
= mStatus_BadParamErr
;
498 log_debug("When adding RRSIG for CNAME, RRSIG does not pass validation"));
502 if (error
!= mStatus_NoError
) {
503 if (rrsig
!= mDNSNULL
) list_delete_node_with_data_ptr(rrsig_records
, rrsig
);
504 if (cname
!= mDNSNULL
) list_delete_node_with_data_ptr(cname_records
, cname
);
509 //======================================================================================================================
510 // add_to_nsec_with_rrsig_t
511 //======================================================================================================================
514 add_to_nsec_with_rrsig_t(nsecs_with_rrsig_t
* const _Nonnull nsecs_with_rrisg
, ResourceRecord
* const _Nonnull rr
) {
515 mStatus error
= mStatus_NoError
;
516 list_t
* const nsec_list
= &nsecs_with_rrisg
->nsec_and_rrsigs_same_name
;
517 const mDNSu8
* const owner_name
= rr
->name
->c
;
518 const mDNSu32 name_hash
= DomainNameHashValue(rr
->name
);
519 mDNSBool is_valid
= mDNSfalse
;
520 const mDNSu8
* owner_name_to_compare
;
521 mDNSu32 name_hash_to_compare
;
523 if (rr
->rrtype
== kDNSType_NSEC
) {
524 one_nsec_with_rrsigs_t
* new_one_nsec
= mDNSNULL
;
525 for (list_node_t
* nsec_node
= list_get_first(nsec_list
);
526 !list_has_ended(nsec_list
, nsec_node
);
527 nsec_node
= list_next(nsec_node
)) {
528 one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
* const)nsec_node
->data
;
529 if (one_nsec
->owner_name
!= mDNSNULL
) {
530 owner_name_to_compare
= one_nsec
->owner_name
;
531 name_hash_to_compare
= one_nsec
->nsec_record
.dnssec_rr
.name_hash
;
533 require_action_quiet(name_hash_to_compare
!= name_hash
|| !DOMAIN_NAME_EQUALS(owner_name_to_compare
, owner_name
),
534 insert_nsec_exit
, error
= mStatus_BadParamErr
;
535 log_debug("two NSEC records have the same owner name - owner name: " PRI_DM_NAME
,
536 DM_NAME_PARAM((const domainname
*)owner_name
))
540 require_action(!list_empty(&one_nsec
->rrsig_records
), insert_nsec_exit
, error
= mStatus_Invalid
;
541 log_error("empty one_nsec_with_rrsigs_t created"));
543 const dnssec_rrsig_t
* const first_rrsig
= (const dnssec_rrsig_t
* const)(list_get_first(&one_nsec
->rrsig_records
)->data
);
544 owner_name_to_compare
= first_rrsig
->dnssec_rr
.name
.c
;
545 name_hash_to_compare
= first_rrsig
->dnssec_rr
.name_hash
;
547 if (name_hash_to_compare
!= name_hash
|| !DOMAIN_NAME_EQUALS(owner_name_to_compare
, owner_name
)) {
551 is_valid
= initialize_dnssec_nsec_t(&one_nsec
->nsec_record
, rr
);
552 require_action_quiet(is_valid
, insert_nsec_exit
, error
= mStatus_BadParamErr
;
553 log_debug("NSEC record initialization failed because of the malformated resource record"));
554 one_nsec
->owner_name
= one_nsec
->nsec_record
.dnssec_rr
.name
.c
;
555 error
= mStatus_NoError
;
556 goto insert_nsec_exit
;
560 // insert new one_nsec
561 error
= list_append_uinitialized(nsec_list
, sizeof(one_nsec_with_rrsigs_t
), (void **)&new_one_nsec
);
562 require_action(error
== mStatus_NoError
, insert_nsec_exit
, log_error("list_append_uinitialized failed;"));
564 is_valid
= initialize_one_nsec_with_rrsigs_t(new_one_nsec
, rr
);
565 require_action_quiet(is_valid
, insert_nsec_exit
, error
= mStatus_BadParamErr
;
566 log_debug("One NSEC structure initialization failed because of malformated resource record - owner name: " PRI_DM_NAME
,
567 DM_NAME_PARAM(rr
->name
))
570 error
= mStatus_NoError
;
572 if (error
!= mStatus_NoError
) {
573 if (new_one_nsec
!= mDNSNULL
) {
574 list_delete_node_with_data_ptr(nsec_list
, new_one_nsec
);
577 } else if (rr
->rrtype
== kDNSType_RRSIG
&& get_covered_type_of_dns_type_rrsig_t(rr
->rdata
->u
.data
) == kDNSType_NSEC
) {
578 list_t
* list_to_insert
= mDNSNULL
;
579 one_nsec_with_rrsigs_t
* new_one_nsec
= mDNSNULL
;
580 dnssec_rrsig_t
* new_rrsig
= mDNSNULL
;
582 for (list_node_t
* nsec_node
= list_get_first(&nsecs_with_rrisg
->nsec_and_rrsigs_same_name
);
583 !list_has_ended(nsec_list
, nsec_node
);
584 nsec_node
= list_next(nsec_node
)) {
585 one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
* const)nsec_node
->data
;
587 if (one_nsec
->owner_name
!= mDNSNULL
) {
588 owner_name_to_compare
= one_nsec
->owner_name
;
589 name_hash_to_compare
= one_nsec
->nsec_record
.dnssec_rr
.name_hash
;
590 } else if (!list_empty(&one_nsec
->rrsig_records
)) {
591 const dnssec_rrsig_t
* const first_rrsig
= (const dnssec_rrsig_t
* const)(list_get_first(&one_nsec
->rrsig_records
)->data
);
592 owner_name_to_compare
= first_rrsig
->dnssec_rr
.name
.c
;
593 name_hash_to_compare
= first_rrsig
->dnssec_rr
.name_hash
;
595 error
= mStatus_Invalid
;
596 log_error("empty one_nsec_with_rrsigs_t created - rr owner name: " PRI_DM_NAME
, DM_NAME_PARAM(rr
->name
));
597 goto insert_rrsig_exit
;
600 if (name_hash_to_compare
== name_hash
&& DOMAIN_NAME_EQUALS(owner_name_to_compare
, owner_name
)) {
601 list_to_insert
= &one_nsec
->rrsig_records
;
606 if (list_to_insert
== mDNSNULL
) {
607 // insert new one_nsec
608 error
= list_append_uinitialized(nsec_list
, sizeof(one_nsec_with_rrsigs_t
), (void **)&new_one_nsec
);
609 require_action(error
== mStatus_NoError
, insert_rrsig_exit
, log_error("list_append_uinitialized failed;"));
611 new_one_nsec
->owner_name
= mDNSNULL
;
612 list_init(&new_one_nsec
->rrsig_records
, sizeof(dnssec_rrsig_t
));
614 list_to_insert
= &new_one_nsec
->rrsig_records
;
618 error
= list_append_uinitialized(list_to_insert
, sizeof(dnssec_rrsig_t
), (void **)&new_rrsig
);
619 require_action(error
== mStatus_NoError
, insert_rrsig_exit
, log_error("list_append_uinitialized failed;"));
621 is_valid
= initialize_dnssec_rrsig_t(new_rrsig
, rr
);
622 require_action_quiet(is_valid
, insert_rrsig_exit
, error
= mStatus_BadParamErr
;
623 log_debug("When adding RRSIG for NSEC, RRSIG does not pass validation"));
626 if (error
!= mStatus_NoError
) {
627 if (new_rrsig
!= mDNSNULL
) {
628 list_delete_node_with_data_ptr(list_to_insert
, new_rrsig
);
630 if (new_one_nsec
!= mDNSNULL
) {
631 list_delete_node_with_data_ptr(nsec_list
, new_one_nsec
);
635 if (rr
->rrtype
!= kDNSType_RRSIG
) {
637 dnssec_rr_t
*dnssec_rr
= mDNSNULL
;
638 error
= list_append_uinitialized(&nsecs_with_rrisg
->wildcard_answers
, sizeof(dnssec_rr_t
), (void **)&dnssec_rr
);
639 require_action(error
== mStatus_NoError
, exit
, log_error("list_append_uinitialized failed;"));
641 initialize_dnssec_rr_t(dnssec_rr
, rr
);
644 dnssec_rrsig_t
*dnssec_rrsig
= mDNSNULL
;
645 error
= list_append_uinitialized(&nsecs_with_rrisg
->wildcard_rrsigs
, sizeof(dnssec_rrsig_t
), (void **)&dnssec_rrsig
);
646 require_action(error
== mStatus_NoError
, exit
, log_error("list_append_uinitialized failed;"));
648 is_valid
= initialize_dnssec_rrsig_t(dnssec_rrsig
, rr
);
649 require_action_quiet(is_valid
, insert_wildcard_rrsig_exit
, error
= mStatus_BadParamErr
;
650 log_debug("When adding RRSIG for wildcard answer, RRSIG does not pass validation"));
652 insert_wildcard_rrsig_exit
:
653 if (error
!= mStatus_NoError
) {
654 if (dnssec_rrsig
!= mDNSNULL
) {
655 list_delete_node_with_data_ptr(&nsecs_with_rrisg
->wildcard_rrsigs
, dnssec_rrsig
);
665 //======================================================================================================================
666 // add_to_nsec3_with_rrsig_t
667 //======================================================================================================================
670 add_to_nsec3_with_rrsig_t(nsec3s_with_rrsig_t
* const _Nonnull nsec3s_with_rrisg
, ResourceRecord
* const _Nonnull rr
) {
671 mStatus error
= mStatus_NoError
;
672 list_t
* const nsec3_list
= &nsec3s_with_rrisg
->nsec3_and_rrsigs_same_name
;
673 const mDNSu8
* const owner_name
= rr
->name
->c
;
674 const mDNSu32 name_hash
= DomainNameHashValue(rr
->name
);
675 mDNSBool is_valid
= mDNStrue
;
676 const mDNSu8
* owner_name_to_compare
;
677 mDNSu32 name_hash_to_compare
;
679 if (rr
->rrtype
== kDNSType_NSEC3
) {
680 one_nsec3_with_rrsigs_t
* new_one_nsec3
= mDNSNULL
;
681 for (list_node_t
*nsec3_node
= list_get_first(nsec3_list
); !list_has_ended(nsec3_list
, nsec3_node
); nsec3_node
= list_next(nsec3_node
)) {
682 one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
* const)nsec3_node
->data
;
683 if (one_nsec3
->owner_name
!= mDNSNULL
) {
684 owner_name_to_compare
= one_nsec3
->owner_name
;
685 name_hash_to_compare
= one_nsec3
->nsec3_record
.dnssec_rr
.name_hash
;
687 require_action_quiet(name_hash_to_compare
!= name_hash
|| !DOMAIN_NAME_EQUALS(owner_name_to_compare
, owner_name
),
688 insert_nsec3_exit
, error
= mStatus_BadParamErr
;
689 log_debug("two NSEC3 records have the same owner name - owner name: " PRI_DM_NAME
,
690 DM_NAME_PARAM((const domainname
*)owner_name
))
693 require_action(!list_empty(&one_nsec3
->rrsig_records
), exit
, error
= mStatus_Invalid
;
694 log_error("empty one_nsec3_with_rrsigs_t created"));
696 const dnssec_rrsig_t
* const first_rrsig
= (const dnssec_rrsig_t
* const)(list_get_first(&one_nsec3
->rrsig_records
)->data
);
697 owner_name_to_compare
= first_rrsig
->dnssec_rr
.name
.c
;
698 name_hash_to_compare
= first_rrsig
->dnssec_rr
.name_hash
;
700 if (name_hash_to_compare
!= name_hash
|| !DOMAIN_NAME_EQUALS(owner_name_to_compare
, owner_name
)) {
704 is_valid
= initialize_dnssec_nsec3_t(&one_nsec3
->nsec3_record
, rr
);
705 require_action_quiet(is_valid
, insert_nsec3_exit
, error
= mStatus_BadParamErr
;
706 log_debug("NSEC record initialization failed because of the malformated resource record"));
707 one_nsec3
->owner_name
= one_nsec3
->nsec3_record
.dnssec_rr
.name
.c
;
708 error
= mStatus_NoError
;
709 goto insert_nsec3_exit
;
713 // insert new one_nsec3
714 error
= list_append_uinitialized(nsec3_list
, sizeof(one_nsec3_with_rrsigs_t
), (void **)&new_one_nsec3
);
715 require_action(error
== mStatus_NoError
, insert_nsec3_exit
, log_error("list_append_uinitialized failed;"));
717 is_valid
= initialize_one_nsec3_with_rrsigs_t(new_one_nsec3
, rr
);
718 require_action_quiet(is_valid
, insert_nsec3_exit
, error
= mStatus_BadParamErr
;
719 log_debug("One NSEC3 structure initialization failed because of malformated resource record - owner name: " PRI_DM_NAME
,
720 DM_NAME_PARAM(rr
->name
))
724 if (error
!= mStatus_NoError
) {
725 if (new_one_nsec3
!= mDNSNULL
) {
726 list_delete_node_with_data_ptr(nsec3_list
, new_one_nsec3
);
729 } else if (rr
->rrtype
== kDNSType_RRSIG
&& get_covered_type_of_dns_type_rrsig_t(rr
->rdata
->u
.data
) == kDNSType_NSEC3
) {
730 list_t
* list_to_insert
= mDNSNULL
;
731 one_nsec3_with_rrsigs_t
* new_one_nsec3
= mDNSNULL
;
732 dnssec_rrsig_t
* new_rrsig
= mDNSNULL
;
734 for (list_node_t
*nsec3_node
= list_get_first(nsec3_list
); !list_has_ended(nsec3_list
, nsec3_node
); nsec3_node
= list_next(nsec3_node
)) {
735 one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
* const)nsec3_node
->data
;
737 if (one_nsec3
->owner_name
!= mDNSNULL
) {
738 owner_name_to_compare
= one_nsec3
->owner_name
;
739 name_hash_to_compare
= one_nsec3
->nsec3_record
.dnssec_rr
.name_hash
;
740 } else if (!list_empty(&one_nsec3
->rrsig_records
)) {
741 const dnssec_rrsig_t
* const first_rrsig
= (const dnssec_rrsig_t
* const)(list_get_first(&one_nsec3
->rrsig_records
)->data
);
742 owner_name_to_compare
= first_rrsig
->dnssec_rr
.name
.c
;
743 name_hash_to_compare
= first_rrsig
->dnssec_rr
.name_hash
;
745 error
= mStatus_Invalid
;
746 log_error("empty one_nsec3_with_rrsigs_t created - rr owner name: " PRI_DM_NAME
, DM_NAME_PARAM(rr
->name
));
747 goto insert_rrsig_exit
;
750 if (name_hash_to_compare
== name_hash
&& DOMAIN_NAME_EQUALS(owner_name_to_compare
, owner_name
)) {
751 list_to_insert
= &one_nsec3
->rrsig_records
;
755 if (list_to_insert
== mDNSNULL
) {
756 // insert new one_nsec3
757 error
= list_append_uinitialized(nsec3_list
, sizeof(one_nsec3_with_rrsigs_t
), (void **)&new_one_nsec3
);
758 require_action(error
== mStatus_NoError
, insert_rrsig_exit
, log_error("list_append_uinitialized failed"));
760 new_one_nsec3
->owner_name
= mDNSNULL
;
761 list_init(&new_one_nsec3
->rrsig_records
, sizeof(dnssec_rrsig_t
));
763 list_to_insert
= &new_one_nsec3
->rrsig_records
;
767 error
= list_append_uinitialized(list_to_insert
, sizeof(dnssec_rrsig_t
), (void **)&new_rrsig
);
768 require_action(error
== mStatus_NoError
, insert_rrsig_exit
, log_error("list_append_uinitialized failed;"));
770 is_valid
= initialize_dnssec_rrsig_t(new_rrsig
, rr
);
771 require_action_quiet(is_valid
, insert_rrsig_exit
, error
= mStatus_BadParamErr
;
772 log_debug("When adding RRSIG for NSEC3, RRSIG does not pass validation"));
775 if (error
!= mStatus_NoError
) {
776 if (new_rrsig
!= mDNSNULL
) {
777 list_delete_node_with_data_ptr(list_to_insert
, new_rrsig
);
779 if (new_one_nsec3
!= mDNSNULL
) {
780 list_delete_node_with_data_ptr(nsec3_list
, new_one_nsec3
);
784 if (rr
->rrtype
!= kDNSType_RRSIG
) {
786 dnssec_rr_t
*dnssec_rr
= mDNSNULL
;
787 error
= list_append_uinitialized(&nsec3s_with_rrisg
->wildcard_answers
, sizeof(dnssec_rr_t
), (void **)&dnssec_rr
);
788 require_action(error
== mStatus_NoError
, exit
, log_error("list_append_uinitialized failed;"));
790 initialize_dnssec_rr_t(dnssec_rr
, rr
);
793 dnssec_rrsig_t
*dnssec_rrsig
= mDNSNULL
;
794 error
= list_append_uinitialized(&nsec3s_with_rrisg
->wildcard_rrsigs
, sizeof(dnssec_rrsig_t
), (void **)&dnssec_rrsig
);
795 require_action(error
== mStatus_NoError
, exit
, log_error("list_append_uinitialized failed;"));
797 is_valid
= initialize_dnssec_rrsig_t(dnssec_rrsig
, rr
);
798 require_action_quiet(is_valid
, insert_wildcard_rrsig_exit
, error
= mStatus_BadParamErr
;
799 log_debug("When adding RRSIG for wildcard answer, RRSIG does not pass validation"));
801 insert_wildcard_rrsig_exit
:
802 if (error
!= mStatus_NoError
) {
803 if (dnssec_rrsig
!= mDNSNULL
) {
804 list_delete_node_with_data_ptr(&nsec3s_with_rrisg
->wildcard_rrsigs
, dnssec_rrsig
);
814 //======================================================================================================================
815 // add_to_originals_with_rrsig_t
816 //======================================================================================================================
819 add_to_originals_with_rrsig_t(
820 originals_with_rrsig_t
* const _Nonnull originals_with_rrisg
,
821 ResourceRecord
* const _Nonnull rr
,
822 const mDNSBool answer_from_cache
,
823 const DNSServiceErrorType dns_error
,
824 const QC_result qc_result
) {
826 mStatus error
= mStatus_NoError
;
828 if (originals_with_rrisg
->type
== original_response
) {
829 dnssec_rrsig_t
* rrsig
= mDNSNULL
;
830 dnssec_original_t
* original
= mDNSNULL
;
832 if (rr
->rrtype
== kDNSType_RRSIG
) {
833 // the corresponding RRISG that covers the requested RR, and RRSIG cannot be the requested
834 error
= list_append_uinitialized(&originals_with_rrisg
->u
.original
.rrsig_records
, sizeof(dnssec_rrsig_t
), (void **)&rrsig
);
835 require_action(error
== mStatus_NoError
, original_response_exit
, log_debug("list_add_front_uinitialized failed; error_description='%s'", mStatusDescription(error
)));
837 mDNSBool is_rrsig_valid
= initialize_dnssec_rrsig_t(rrsig
, rr
);
838 require_action_quiet(is_rrsig_valid
, original_response_exit
, error
= mStatus_BadParamErr
;
839 log_debug("When adding RRSIG for original response, RRSIG does not pass validation"));
841 error
= list_append_uinitialized(&originals_with_rrisg
->u
.original
.original_records
, sizeof(dnssec_original_t
), (void **)&original
);
842 require_action(error
== mStatus_NoError
, original_response_exit
, log_debug("list_add_front_uinitialized failed; error_description='%s'", mStatusDescription(error
)));
844 initialize_dnssec_original_t(original
, rr
, answer_from_cache
, dns_error
, qc_result
);
847 original_response_exit
:
848 if (error
!= mStatus_NoError
) {
849 if (original
!= mDNSNULL
) list_delete_node_with_data_ptr(&originals_with_rrisg
->u
.original
.original_records
, (void *)original
);
850 if (rrsig
!= mDNSNULL
) list_delete_node_with_data_ptr(&originals_with_rrisg
->u
.original
.rrsig_records
, (void *)rrsig
);
853 } else if (originals_with_rrisg
->type
== cname_response
) {
854 error
= add_to_cname_with_rrsig_t(&originals_with_rrisg
->u
.cname_with_rrsig
, rr
);
855 require_action(error
== mStatus_NoError
, exit
, log_debug("add_to_cname_with_rrsig_t failed; error_description='%s'", mStatusDescription(error
)));
856 } else if (originals_with_rrisg
->type
== nsec_response
) {
857 error
= add_to_nsec_with_rrsig_t(&originals_with_rrisg
->u
.nsecs_with_rrsig
, rr
);
858 require_action(error
== mStatus_NoError
, exit
, log_debug("add_to_nsec_with_rrsig_t failed; error_description='%s'", mStatusDescription(error
)));
859 } else if (originals_with_rrisg
->type
== nsec3_response
) {
860 error
= add_to_nsec3_with_rrsig_t(&originals_with_rrisg
->u
.nsec3s_with_rrsig
, rr
);
861 require_action(error
== mStatus_NoError
, exit
, log_debug("add_to_nsec3_with_rrsig_t failed; error_description='%s'", mStatusDescription(error
)));
870 //======================================================================================================================
871 // dnskeys_with_rrsig_t functions
872 //======================================================================================================================
874 //======================================================================================================================
875 // add_to_dnskeys_with_rrsig_t
876 //======================================================================================================================
879 add_to_dnskeys_with_rrsig_t(dnskeys_with_rrsig_t
* const _Nonnull dnskeys_with_rrsig
, ResourceRecord
* const _Nonnull rr
) {
880 // dnskeys_with_rrsig != mDNSNULL && rr != mDNSNULL
881 mStatus error
= mStatus_NoError
;
882 mDNSBool is_valid
= mDNStrue
;
884 dnssec_dnskey_t
* dnskey
= mDNSNULL
;
885 dnssec_rrsig_t
* rrsig
= mDNSNULL
;
887 if (rr
->rrtype
== kDNSType_DNSKEY
) {
888 error
= list_append_uinitialized(&dnskeys_with_rrsig
->dnskey_records
, sizeof(dnssec_dnskey_t
), (void **)&dnskey
);
889 require_action(error
== mStatus_NoError
, original_response_exit
, log_debug("list_append_uinitialized failed; error_description='%s'", mStatusDescription(error
)));
891 is_valid
= initialize_dnssec_dnskey_t(dnskey
, rr
);
892 require_action_quiet(is_valid
, original_response_exit
, error
= mStatus_BadParamErr
;
893 log_debug("When adding DNSKEY rdata for DNSKEY, rdata does not pass validation and does not get added"));
895 verify(rr
->rrtype
== kDNSType_RRSIG
);
896 error
= list_append_uinitialized(&dnskeys_with_rrsig
->rrsig_records
, sizeof(dnssec_rrsig_t
), (void **)&rrsig
);
897 require_action(error
== mStatus_NoError
, original_response_exit
, log_debug("list_append_uinitialized failed; error_description='%s'", mStatusDescription(error
)));
899 is_valid
= initialize_dnssec_rrsig_t(rrsig
, rr
);
900 require_action_quiet(is_valid
, original_response_exit
, error
= mStatus_BadParamErr
;
901 log_debug("When adding RRSIG for DNSKEY, RRSIG does not pass validation and does not get added"));
904 original_response_exit
:
905 if (error
!= mStatus_NoError
) {
906 if (dnskey
!= mDNSNULL
) list_delete_node_with_data_ptr(&dnskeys_with_rrsig
->dnskey_records
, dnskey
);
907 if (rrsig
!= mDNSNULL
) list_delete_node_with_data_ptr(&dnskeys_with_rrsig
->rrsig_records
, rrsig
);
912 //======================================================================================================================
913 // add_to_dses_with_rrsig_t
914 //======================================================================================================================
917 add_to_dses_with_rrsig_t(dses_with_rrsig_t
* const _Nonnull dses_with_rrsig
, ResourceRecord
* const _Nonnull rr
) {
918 mStatus error
= mStatus_NoError
;
919 mDNSBool is_valid
= mDNSfalse
;
921 if (dses_with_rrsig
->type
== original_response
) {
922 dnssec_ds_t
* ds
= mDNSNULL
;
923 dnssec_rrsig_t
*rrsig
= mDNSNULL
;
925 if (rr
->rrtype
== kDNSType_DS
) {
926 error
= list_append_uinitialized(&dses_with_rrsig
->u
.original
.ds_records
, sizeof(dnssec_ds_t
), (void **)&ds
);
927 require_action(error
== mStatus_NoError
, original_response_exit
, log_debug("list_append_uinitialized failed; error_description='%s'", mStatusDescription(error
)));
929 is_valid
= initialize_dnssec_ds_t(ds
, rr
);
930 require_action_quiet(is_valid
, original_response_exit
, error
= mStatus_BadParamErr
;
931 log_debug("When adding DS rdata for DS, the rdata does not pass validation and does not get added"));
933 verify(rr
->rrtype
== kDNSType_RRSIG
);
934 error
= list_append_uinitialized(&dses_with_rrsig
->u
.original
.rrsig_records
, sizeof(dnssec_rrsig_t
), (void **)&rrsig
);
935 require_action(error
== mStatus_NoError
, original_response_exit
, log_debug("list_append_uinitialized failed; error_description='%s'", mStatusDescription(error
)));
937 is_valid
= initialize_dnssec_rrsig_t(rrsig
, rr
);
938 require_action_quiet(is_valid
, original_response_exit
, error
= mStatus_BadParamErr
;
939 log_debug("When adding RRSIG for DS, RRSIG does not pass validation and does not get added"));
941 original_response_exit
:
942 if (error
!= mStatus_NoError
) {
943 if (ds
!= mDNSNULL
) list_delete_node_with_data_ptr(&dses_with_rrsig
->u
.original
.ds_records
, (void *)ds
);
944 if (rrsig
!= mDNSNULL
) list_delete_node_with_data_ptr(&dses_with_rrsig
->u
.original
.rrsig_records
, (void *)rrsig
);
947 }else if (dses_with_rrsig
->type
== nsec_response
) {
948 error
= add_to_nsec_with_rrsig_t(&dses_with_rrsig
->u
.nsecs_with_rrsig
, rr
);
949 require_action(error
== mStatus_NoError
, exit
, log_debug("add_to_nsec_with_rrsig_t failed; error_description='%s'", mStatusDescription(error
)));
950 } else if (dses_with_rrsig
->type
== nsec3_response
) {
951 error
= add_to_nsec3_with_rrsig_t(&dses_with_rrsig
->u
.nsec3s_with_rrsig
, rr
);
952 require_action(error
== mStatus_NoError
, exit
, log_debug("add_to_nsec3_with_rrsig_t failed; error_description='%s'", mStatusDescription(error
)));
954 error
= mStatus_Invalid
;
955 log_error("invalid response type for DS record");
962 //======================================================================================================================
963 // initialize_denial_of_existence_records_t
964 //======================================================================================================================
966 mDNSexport denial_of_existence_records_t
* _Nullable
967 create_denial_of_existence_records_t(void) {
968 denial_of_existence_records_t
*denial
= malloc(sizeof(denial_of_existence_records_t
));
969 require_quiet(denial
!= mDNSNULL
, exit
);
971 list_init(&denial
->resource_records
, sizeof(ResourceRecord
));
977 //======================================================================================================================
978 // destroy_denial_of_existence_records_t
979 //======================================================================================================================
982 destroy_denial_of_existence_records_t(denial_of_existence_records_t
* const _Nonnull denial_of_existence_records
) {
983 list_t
*denial_rrs
= &denial_of_existence_records
->resource_records
;
984 for (const list_node_t
*rr_node
= list_get_first(denial_rrs
); !list_has_ended(denial_rrs
, rr_node
); rr_node
= list_next(rr_node
)) {
985 ResourceRecord
* const rr
= (ResourceRecord
*)rr_node
->data
;
986 free_resource_record_deep_copied(rr
);
988 list_uninit(denial_rrs
);
989 free(denial_of_existence_records
);
993 destroy_denial_of_existence_records_t_if_nonnull(denial_of_existence_records_t
* const _Nonnull denial_of_existence_records
) {
994 if (denial_of_existence_records
== mDNSNULL
) {
998 destroy_denial_of_existence_records_t(denial_of_existence_records
);
1001 //======================================================================================================================
1002 // add_to_denial_of_existence_records_t
1003 //======================================================================================================================
1006 add_to_denial_of_existence_records_t(denial_of_existence_records_t
* const _Nonnull denial_of_existence_records
, const ResourceRecord
* const _Nonnull rr
) {
1007 mStatus error
= mStatus_NoError
;
1008 list_t
* resource_records
= &denial_of_existence_records
->resource_records
;
1009 ResourceRecord
*rr_copy
;
1011 error
= list_append_uinitialized(resource_records
, sizeof(ResourceRecord
), (void **)&rr_copy
);
1012 require_action(error
== mStatus_NoError
, exit
, log_debug("list_append_uinitialized failed; error_description='%s'", mStatusDescription(error
)));
1014 error
= deep_copy_resource_record(rr_copy
, rr
);
1015 require_action(error
== mStatus_NoError
, exit
, log_error("initialize_dnssec_rr_t failed"));
1021 //======================================================================================================================
1022 // add_to_dnssec_zone_t
1023 //======================================================================================================================
1026 add_to_dnssec_zone_t(
1027 dnssec_zone_t
* const _Nonnull zone
,
1028 ResourceRecord
* const _Nonnull rr
,
1029 const mDNSu16 question_type
) {
1031 mStatus error
= mStatus_NoError
;
1033 if (question_type
== kDNSType_DNSKEY
) {
1034 error
= add_to_dnskeys_with_rrsig_t(&zone
->dnskeys_with_rrsig
, rr
);
1035 require_action_quiet(error
== mStatus_NoError
, exit
, log_debug("add_to_dnskeys_with_rrsig_t failed; error_description='%s'", mStatusDescription(error
)));
1036 } else if (question_type
== kDNSType_DS
) {
1037 if (!zone
->dses_initialized
) {
1038 response_type_t type
= determine_response_type(rr
->rrtype
, rr
->rdata
->u
.data
, question_type
);
1039 require_action_quiet(type
!= unknown_response
, exit
, error
= mStatus_Invalid
;
1040 log_error("Unrelated response to current query; question_type=" PUB_S
", response_type=" PUB_S
,
1041 DNS_TYPE_STR(question_type
), DNS_TYPE_STR(rr
->rrtype
)));
1042 initialize_dses_with_rrsig_t(&zone
->dses_with_rrsig
, type
);
1043 zone
->dses_initialized
= mDNStrue
;
1045 error
= add_to_dses_with_rrsig_t(&zone
->dses_with_rrsig
, rr
);
1046 require_action_quiet(error
== mStatus_NoError
, exit
, log_debug("add_to_dses_with_rrsig_t failed; error_description='%s'", mStatusDescription(error
)));
1048 error
= mStatus_Invalid
;
1049 log_error("Non DS/DNSKEY query created for dnssec zone; qtype=" PUB_S
, DNS_TYPE_STR(question_type
));
1056 #pragma mark - Update DNSSEC Records
1058 #pragma mark - update_dnssec_zone_t_from_cache_for_no_error_response
1061 get_time_received_for_answer(
1062 const CacheGroup
* const _Nonnull cache_group
,
1063 const ResourceRecord
* const _Nonnull answer
);
1066 get_updated_type_from_answer(const ResourceRecord
* const _Nonnull answer
);
1068 mDNSexport dnssec_retrieval_result_t
1069 update_dnssec_zone_t_from_cache_for_no_error_response(
1070 const mDNS
* const _Nonnull m
,
1071 const DNSQuestion
* const _Nonnull question
,
1072 const ResourceRecord
* const _Nonnull answer
,
1073 const QC_result add_record
,
1074 dnssec_zone_t
* const _Nonnull zone
) {
1076 dnssec_retrieval_result_t result
= dnssec_retrieval_unknown_error
;
1078 const CacheGroup
* cache_group
;
1079 mDNSs32 last_time_received
;
1080 mDNSu16 updated_type
;
1081 const dnssec_context_t
* const context
= question
->DNSSECStatus
.context
;
1082 mDNSu32 request_id
= context
->original
.original_parameters
.request_id
;
1083 mDNSu16 question_id
= mDNSVal16(question
->TargetQID
);
1085 require_action_quiet(question
->qtype
== kDNSType_DS
|| question
->qtype
== kDNSType_DNSKEY
, exit
,
1086 result
= dnssec_retrieval_non_dnskey_ds_record_for_zone
;
1087 log_error("Non DS/DNSKEY query created for dnssec zone; qtype=" PUB_S
, DNS_TYPE_STR(question
->qtype
)));
1089 cache_group
= CacheGroupForName(m
, question
->qnamehash
, &question
->qname
);
1090 require_action_quiet(cache_group
!= mDNSNULL
, exit
,
1091 log_error("The question deos not have any corresponding cache group; qname=" PRI_DM_NAME
,
1092 DM_NAME_PARAM(&question
->qname
)));
1094 last_time_received
= get_time_received_for_answer(cache_group
, answer
);
1095 require_action_quiet(last_time_received
!= 0, exit
,
1096 log_error("Did not find answer in the cache group; qname=" PRI_DM_NAME
" answer_name=" PRI_DM_NAME
,
1097 DM_NAME_PARAM(&question
->qname
), DM_NAME_PARAM(answer
->name
)));
1099 updated_type
= get_updated_type_from_answer(answer
);
1100 require_action_quiet(question
->qtype
== updated_type
, exit
, result
= dnssec_retrieval_non_dnskey_ds_record_for_zone
;
1101 log_error("[R%u->%u] Record type is not what question asked for; qname=" PRI_DM_NAME
", qtype=" PUB_S
", rr_type=" PUB_S
,
1102 request_id
, question_id
, DM_NAME_PARAM(&question
->qname
),
1103 DNS_TYPE_STR(question
->qtype
), DNS_TYPE_STR(updated_type
)));
1105 if (updated_type
== kDNSType_DS
) {
1106 require_action_quiet(zone
->ds_request_started
, exit
, result
= dnssec_retrieval_invalid_internal_state
;);
1108 if (add_record
== QC_add
&& zone
->last_time_ds_add
< last_time_received
) {
1109 // having new records added into the response
1110 zone
->last_time_ds_add
= last_time_received
;
1111 } else if (add_record
== QC_rmv
&& zone
->last_time_ds_rmv
< last_time_received
) {
1112 // having old records removed from the response
1113 zone
->last_time_ds_rmv
= last_time_received
;
1114 uninitialize_dses_with_rrsig_t(&zone
->dses_with_rrsig
);
1115 zone
->dses_initialized
= mDNSfalse
;
1116 result
= dnssec_retrieval_waiting_for_records
;
1117 log_default("[R%u->Q%u] Removing DS record from the zone - hostname: " PRI_DM_NAME
, request_id
, question_id
, DM_NAME_PARAM(&zone
->domain_name
));
1120 result
= dnssec_retrieval_no_new_change
;
1123 } else if (updated_type
== kDNSType_DNSKEY
) {
1124 require_action_quiet(zone
->dnskey_request_started
, exit
, result
= dnssec_retrieval_invalid_internal_state
;);
1126 if (add_record
== QC_add
&& zone
->last_time_dnskey_add
< last_time_received
) {
1127 // having new records added into the response
1128 zone
->last_time_dnskey_add
= last_time_received
;
1129 } else if (add_record
== QC_rmv
&& zone
->last_time_dnskey_rmv
< last_time_received
) {
1130 // having old records removed from the response
1131 zone
->last_time_dnskey_rmv
= last_time_received
;
1132 // uninitialize and initialize to clear all the old contents in zone->dnskeys_with_rrsig
1133 uninitialize_dnskeys_with_rrsig_t(&zone
->dnskeys_with_rrsig
);
1134 initialize_dnskeys_with_rrsig_t(&zone
->dnskeys_with_rrsig
);
1135 result
= dnssec_retrieval_waiting_for_records
;
1136 log_default("[R%u->Q%u] Removing DNSKEY record from the zone - hostname: " PRI_DM_NAME
, request_id
, question_id
, DM_NAME_PARAM(&zone
->domain_name
));
1139 result
= dnssec_retrieval_no_new_change
;
1143 result
= dnssec_retrieval_non_dnskey_ds_record_for_zone
;
1147 mDNSu32 now
= m
->timenow
;
1148 mDNSBool new_record_added
= mDNSfalse
;
1149 for (CacheRecord
*cache_record
= cache_group
->members
; cache_record
!= mDNSNULL
; cache_record
= cache_record
->next
) {
1150 ResourceRecord
* const rr
= &cache_record
->resrec
;
1151 mDNSBool cache_record_answers_question
= SameNameCacheRecordAnswersQuestion(cache_record
, question
);
1152 if (!cache_record_answers_question
) {
1156 ssize_t remaining_ttl
= (size_t)rr
->rroriginalttl
- (now
- cache_record
->TimeRcvd
) / mDNSPlatformOneSecond
;
1157 if (remaining_ttl
<= 0) {
1158 log_default("Ignoring record: name="PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, remaining_ttl=%zd, rdlength=%d",
1159 DM_NAME_PARAM(rr
->name
), DNSTypeName(rr
->rrtype
), rr
->rroriginalttl
, remaining_ttl
, rr
->rdlength
);
1162 log_default("[R%u->Q%u] Adding record: name="PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, remaining_ttl=%zd, rdlength=%d",
1163 request_id
, question_id
,
1164 DM_NAME_PARAM(rr
->name
), DNSTypeName(rr
->rrtype
), rr
->rroriginalttl
, remaining_ttl
, rr
->rdlength
);
1166 error
= add_to_dnssec_zone_t(zone
, rr
, question
->qtype
);
1167 require_action_quiet(error
== mStatus_NoError
, exit
, result
= dnssec_retrieval_unknown_error
);
1169 if (!new_record_added
) {
1170 new_record_added
= mDNStrue
;
1172 last_time_received
= MAX(last_time_received
, cache_record
->TimeRcvd
);
1175 require_action_quiet(new_record_added
, exit
, result
= dnssec_retrieval_non_dnskey_ds_record_for_zone
;
1176 log_error("[R%u->Q%u] No new record is being added into validation tree, while the TimeRcvd field has a greater value than the last update time of zone - "
1177 "returned rr name: " PRI_DM_NAME
", rr type: " PUB_S
", rr existence type: 0x%X, QC result: %u",
1178 request_id
, question_id
, DM_NAME_PARAM(answer
->name
), DNSTypeName(answer
->rrtype
), answer
->RecordType
, add_record
)
1181 mDNSBool contains_rrsig
= mDNSfalse
;
1182 if (updated_type
== kDNSType_DS
) {
1183 if (new_record_added
) {
1184 zone
->dses_with_rrsig
.set_completed
= mDNStrue
;
1185 zone
->last_time_ds_add
= last_time_received
;
1187 require_action_quiet(zone
->dses_initialized
, exit
, result
= dnssec_retrieval_invalid_internal_state
;
1188 log_error("[R%u->Q%u] Have new records added into DS structure while the DS structure is not initialized"
1189 "returned rr name: " PRI_DM_NAME
", rr type: " PUB_S
", rr existence type: 0x%X, QC result: %u",
1190 request_id
, question_id
, DM_NAME_PARAM(answer
->name
), DNSTypeName(answer
->rrtype
), answer
->RecordType
,
1193 contains_rrsig
= contains_rrsig_in_dses_with_rrsig_t(&zone
->dses_with_rrsig
);
1194 } else if (updated_type
== kDNSType_DNSKEY
) {
1195 if (new_record_added
) {
1196 zone
->dnskeys_with_rrsig
.set_completed
= mDNStrue
;
1197 zone
->last_time_dnskey_add
= last_time_received
;
1199 contains_rrsig
= contains_rrsig_in_dnskeys_with_rrsig_t(&zone
->dnskeys_with_rrsig
);
1201 result
= dnssec_retrieval_non_dnskey_ds_record_for_zone
;
1202 log_error("Non DS/DNSKEY response for DNSSEC zone; rr_type=" PUB_S
, DNS_TYPE_STR(updated_type
));
1205 require_action_quiet(contains_rrsig
, exit
, result
= dnssec_retrieval_no_rrsig
;
1206 log_error("No RRSIG records returned for DNSSEC query; qname=" PRI_DM_NAME
", qtype=" PUB_S
,
1207 DM_NAME_PARAM(&question
->qname
), DNS_TYPE_STR(question
->qtype
)));
1209 result
= dnssec_retrieval_no_error
;
1214 #pragma mark get_time_received_for_answer
1216 get_time_received_for_answer(
1217 const CacheGroup
* const _Nonnull cache_group
,
1218 const ResourceRecord
* const _Nonnull answer
) {
1220 mDNSs32 last_time_received
= 0;
1222 for (CacheRecord
*cache_record
= cache_group
->members
; cache_record
!= mDNSNULL
; cache_record
= cache_record
->next
) {
1223 if (answer
!= &cache_record
->resrec
) {
1227 last_time_received
= cache_record
->TimeRcvd
;
1232 return last_time_received
;
1235 #pragma mark - update_original_from_cache_for_no_error_response
1237 mDNSexport dnssec_retrieval_result_t
1238 update_original_from_cache_for_no_error_response(
1239 mDNS
* const _Nonnull m
,
1240 const DNSQuestion
* const _Nonnull question
,
1241 const ResourceRecord
* const _Nonnull answer
,
1242 const QC_result add_record
,
1243 const DNSServiceErrorType dns_result_error
,
1244 dnssec_context_t
* const _Nonnull dnssec_context
) {
1246 dnssec_retrieval_result_t result
= dnssec_retrieval_unknown_error
;
1247 mStatus error
= mStatus_UnknownErr
;
1248 original_t
* const original
= &dnssec_context
->original
;
1249 originals_with_rrsig_t
* const originals_with_rrsig
= &original
->original_result_with_rrsig
;
1250 const CacheGroup
* cache_group
;
1251 mDNSs32 last_time_received
;
1252 mDNSu32 request_id
= dnssec_context
->original
.original_parameters
.request_id
;
1253 mDNSu16 question_id
= mDNSVal16(question
->TargetQID
);
1255 cache_group
= CacheGroupForName(m
, question
->qnamehash
, &question
->qname
);
1256 require_action_quiet(cache_group
!= mDNSNULL
, exit
, result
= dnssec_retrieval_invalid_internal_state
;
1257 log_error("The question deos not have any corresponding cache group; qname=" PRI_DM_NAME
,
1258 DM_NAME_PARAM(&question
->qname
)));
1260 last_time_received
= get_time_received_for_answer(cache_group
, answer
);
1261 require_action_quiet(last_time_received
!= 0, exit
, result
= dnssec_retrieval_invalid_internal_state
;
1262 log_error("Did not find answer in the cache group; qname=" PRI_DM_NAME
" answer_name=" PRI_DM_NAME
,
1263 DM_NAME_PARAM(&question
->qname
), DM_NAME_PARAM(answer
->name
)));
1265 if (add_record
== QC_add
&& original
->last_time_add
< last_time_received
) {
1266 // having new records added into the response
1267 original
->last_time_add
= last_time_received
;
1269 if (originals_with_rrsig
->type
!= unknown_response
) {
1270 // the previous answer is NSEC, NSEC3 or suppressed fake negative cache
1271 uninitialize_originals_with_rrsig_t(&original
->original_result_with_rrsig
);
1273 } else if (add_record
== QC_rmv
&& original
->last_time_rmv
< last_time_received
) {
1274 // having old records removed from the response
1275 response_type_t original_response_type
= originals_with_rrsig
->type
;
1276 original
->last_time_rmv
= last_time_received
;
1277 require_action_quiet(original_response_type
!= unknown_response
, exit
, result
= dnssec_retrieval_invalid_internal_state
);
1278 uninitialize_originals_with_rrsig_t(&original
->original_result_with_rrsig
);
1280 // check if there is still active sub CNAME request, if so, the CNAME request will be stopped by
1281 // handle_retrieval_result later.
1282 result
= (original_response_type
== cname_response
) ?
1283 dnssec_retrieval_cname_removed
: dnssec_retrieval_waiting_for_records
;
1286 result
= dnssec_retrieval_no_new_change
;
1290 mDNSs32 now
= m
->timenow
;
1291 mDNSBool new_record_added
= mDNSfalse
;
1292 for (CacheRecord
*cache_record
= cache_group
->members
; cache_record
!= mDNSNULL
; cache_record
= cache_record
->next
) {
1293 ResourceRecord
* const rr
= &cache_record
->resrec
;
1294 mDNSBool cache_record_answers_question
= SameNameCacheRecordAnswersQuestion(cache_record
, question
);
1295 if (!cache_record_answers_question
) {
1299 ssize_t remaining_ttl
= (size_t)rr
->rroriginalttl
- (now
- cache_record
->TimeRcvd
) / mDNSPlatformOneSecond
;
1300 if (remaining_ttl
<= 0) {
1301 log_default("Ignoring record: name="PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, remaining_ttl=%zd, rdlength=%d",
1302 DM_NAME_PARAM(rr
->name
), DNSTypeName(rr
->rrtype
), rr
->rroriginalttl
, remaining_ttl
, rr
->rdlength
);
1305 log_default("[R%u->Q%u] Adding record: name="PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, remaining_ttl=%zd, rdlength=%d",
1306 request_id
, question_id
,
1307 DM_NAME_PARAM(rr
->name
), DNSTypeName(rr
->rrtype
), rr
->rroriginalttl
, remaining_ttl
, rr
->rdlength
);
1309 if (originals_with_rrsig
->type
== unknown_response
) {
1310 // this is our first time to add the records into the list
1311 response_type_t type
= determine_response_type(rr
->rrtype
, rr
->rdata
->u
.data
, question
->qtype
);
1312 require_action_quiet(type
!= unknown_response
, exit
, result
= dnssec_retrieval_invalid_internal_state
;
1313 log_error("Unrelated response to current query; question_type=" PUB_S
", response_type=" PUB_S
,
1314 DNS_TYPE_STR(question
->qtype
), DNS_TYPE_STR(answer
->rrtype
)));
1315 initialize_originals_with_rrsig_t(&original
->original_result_with_rrsig
, type
);
1317 if (type
== cname_response
) {
1318 QueryRecordClientRequest
* const primary_request
= GET_PRIMARY_REQUEST(dnssec_context
);
1320 require_action_quiet(primary_request
!= mDNSNULL
, exit
,
1321 result
= dnssec_retrieval_invalid_internal_state
;
1322 log_error("[R%u] primary request has a NULL QueryRecordClientRequest", primary_request
->op
.reqID
));
1324 // increment the referrals.
1325 primary_request
->op
.q
.CNAMEReferrals
++;
1329 error
= add_to_originals_with_rrsig_t(originals_with_rrsig
, rr
, !question
->InitialCacheMiss
, dns_result_error
, add_record
);
1330 require_action_quiet(error
== mStatus_NoError
, exit
, result
= dnssec_retrieval_unknown_error
);
1331 if (!new_record_added
) {
1332 new_record_added
= mDNStrue
;
1334 last_time_received
= MAX(last_time_received
, cache_record
->TimeRcvd
);
1337 if (new_record_added
) {
1338 original
->last_time_add
= last_time_received
;
1340 mDNSBool contains_rrsig
= mDNSfalse
;
1341 contains_rrsig
= contains_rrsig_in_originals_with_rrsig_t(&original
->original_result_with_rrsig
);
1342 require_action_quiet(contains_rrsig
, exit
, result
= dnssec_retrieval_no_rrsig
;
1343 log_error("No RRSIG records returned for DNSSEC query; qname=" PRI_DM_NAME
", qtype=" PUB_S
,
1344 DM_NAME_PARAM(&question
->qname
), DNS_TYPE_STR(question
->qtype
)));
1346 result
= dnssec_retrieval_no_error
;
1351 #pragma mark get_updated_type_from_answer
1353 get_updated_type_from_answer(const ResourceRecord
* const _Nonnull answer
) {
1354 mDNSu16 type
= kDNSQType_ANY
;
1356 if (answer
->rrtype
== kDNSType_RRSIG
) {
1357 type
= get_covered_type_of_dns_type_rrsig_t(answer
->rdata
->u
.data
);
1359 type
= answer
->rrtype
;
1365 #pragma mark - update_original_from_cache_for_denial_of_existence_response
1367 mDNSexport dnssec_retrieval_result_t
1368 update_original_from_cache_for_denial_of_existence_response(
1369 const mDNS
*const _Nonnull m
,
1370 const DNSQuestion
* _Nonnull question
,
1371 ResourceRecord
* const _Nonnull answer
,
1372 const QC_result add_record
,
1373 const DNSServiceErrorType dns_result_error
,
1374 dnssec_context_t
* const _Nonnull dnssec_context
) {
1376 dnssec_retrieval_result_t result
= dnssec_retrieval_unknown_error
;
1378 original_t
* const original
= &dnssec_context
->original
;
1379 originals_with_rrsig_t
* const originals_with_rrsig
= &original
->original_result_with_rrsig
;
1380 const list_t
* denial_rrs
; // list_t<dnssec_rr>
1381 const ResourceRecord
* first_rr
= mDNSNULL
;
1382 const CacheGroup
* cache_group
;
1383 mDNSs32 last_time_received
;
1384 response_type_t type
;
1385 mDNSu32 request_id
= dnssec_context
->original
.original_parameters
.request_id
;
1386 mDNSu16 question_id
= mDNSVal16(question
->TargetQID
);
1387 mDNSBool suppressed
= add_record
== QC_suppressed
;
1389 if (dnssec_context
->denial_of_existence_records
!= mDNSNULL
) {
1390 denial_rrs
= &dnssec_context
->denial_of_existence_records
->resource_records
;
1391 require_action_quiet(!list_empty(denial_rrs
), exit
, result
= dnssec_retrieval_invalid_internal_state
);
1393 denial_rrs
= mDNSNULL
;
1396 cache_group
= CacheGroupForName(m
, question
->qnamehash
, &question
->qname
);
1397 require_action_quiet(cache_group
!= mDNSNULL
|| suppressed
,
1398 exit
, result
= dnssec_retrieval_invalid_internal_state
;
1399 log_error("The question deos not have any corresponding cache group; qname=" PRI_DM_NAME
,
1400 DM_NAME_PARAM(&question
->qname
)));
1402 if (cache_group
!= mDNSNULL
) {
1403 last_time_received
= get_time_received_for_answer(cache_group
, answer
);
1404 require_action_quiet(last_time_received
!= 0, exit
, result
= dnssec_retrieval_invalid_internal_state
;
1405 log_error("Did not find answer in the cache group; qname=" PRI_DM_NAME
" answer_name=" PRI_DM_NAME
,
1406 DM_NAME_PARAM(&question
->qname
), DM_NAME_PARAM(answer
->name
)));
1408 last_time_received
= INT_MIN
;
1411 if ((add_record
== QC_add
&& original
->last_time_add
< last_time_received
) || add_record
== QC_suppressed
) {
1412 // having new records added into the response, since negative answer is mutual exclusive, the previous answer
1414 original
->last_time_add
= last_time_received
;
1415 if (originals_with_rrsig
->type
!= unknown_response
) {
1416 uninitialize_originals_with_rrsig_t(&original
->original_result_with_rrsig
);
1417 original
->last_time_rmv
= last_time_received
;
1420 result
= dnssec_retrieval_no_new_change
;
1424 require_action_quiet(add_record
== QC_add
|| suppressed
,
1425 exit
, result
= dnssec_retrieval_invalid_internal_state
);
1427 if (denial_rrs
!= mDNSNULL
&& !list_empty(denial_rrs
)) {
1428 first_rr
= (ResourceRecord
*)(list_get_first(denial_rrs
)->data
);
1429 type
= determine_response_type(first_rr
->rrtype
, first_rr
->rdata
->u
.data
, question
->qtype
);
1430 require_action_quiet(type
!= unknown_response
, exit
, result
= dnssec_retrieval_invalid_internal_state
;
1431 log_error("Unrelated response to current query; question_type=" PUB_S
", response_type=" PUB_S
,
1432 DNS_TYPE_STR(question
->qtype
), DNS_TYPE_STR(first_rr
->rrtype
)));
1434 type
= original_response
;
1437 initialize_originals_with_rrsig_t(originals_with_rrsig
, type
);
1439 if (type
== nsec_response
) {
1440 original
->original_result_with_rrsig
.u
.nsecs_with_rrsig
.negative_rr
= answer
;
1441 log_default("[R%u->Q%u] Adding negative answer verified by NSEC record; name=" PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, rdlength=%d",
1442 request_id
, question_id
,
1443 DM_NAME_PARAM(answer
->name
), DNSTypeName(answer
->rrtype
), answer
->rroriginalttl
, answer
->rdlength
);
1444 } else if (type
== nsec3_response
) {
1445 original
->original_result_with_rrsig
.u
.nsec3s_with_rrsig
.negative_rr
= answer
;
1446 log_default("[R%u->Q%u] Adding negative answer verified by NSEC3 record; name=" PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, rdlength=%d",
1447 request_id
, question_id
,
1448 DM_NAME_PARAM(answer
->name
), DNSTypeName(answer
->rrtype
), answer
->rroriginalttl
, answer
->rdlength
);
1449 } else if (type
== original_response
) {
1450 original
->original_result_with_rrsig
.u
.original
.negative_rr
= answer
;
1451 original
->original_result_with_rrsig
.u
.original
.suppressed_response
= suppressed
;
1453 log_default("[R%u->Q%u] Adding negative answer not verified by any DNSSEC record; name=" PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, rdlength=%d",
1454 request_id
, question_id
,
1455 DM_NAME_PARAM(answer
->name
), DNSTypeName(answer
->rrtype
), answer
->rroriginalttl
, answer
->rdlength
);
1457 log_default("[R%u->Q%u] Adding negative answer suppressed by mDNSResponder; name=" PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, rdlength=%d",
1458 request_id
, question_id
,
1459 DM_NAME_PARAM(answer
->name
), DNSTypeName(answer
->rrtype
), answer
->rroriginalttl
, answer
->rdlength
);
1460 print_dnssec_context_t(dnssec_context
);
1463 result
= dnssec_retrieval_invalid_internal_state
;
1467 if (denial_rrs
!= mDNSNULL
) {
1468 for (const list_node_t
*rr_node
= list_get_first(denial_rrs
); !list_has_ended(denial_rrs
, rr_node
); rr_node
= list_next(rr_node
)) {
1469 ResourceRecord
* const rr
= (ResourceRecord
*)rr_node
->data
;
1471 log_default("[R%u->Q%u] Adding denial of existence record: name=" PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, rdlength=%d",
1472 request_id
, question_id
,
1473 DM_NAME_PARAM(rr
->name
), DNSTypeName(rr
->rrtype
), rr
->rroriginalttl
, rr
->rdlength
);
1475 error
= add_to_originals_with_rrsig_t(&original
->original_result_with_rrsig
, rr
, !question
->InitialCacheMiss
, dns_result_error
, add_record
);
1476 require_action_quiet(error
== mStatus_NoError
, exit
, result
= dnssec_retrieval_unknown_error
);
1480 mDNSBool contains_rrsig
= mDNSfalse
;
1481 contains_rrsig
= contains_rrsig_in_originals_with_rrsig_t(&original
->original_result_with_rrsig
);
1482 require_action_quiet(contains_rrsig
|| suppressed
, exit
, result
= dnssec_retrieval_no_rrsig
;
1483 log_error("No RRSIG records returned for DNSSEC query; qname=" PRI_DM_NAME
", rr_type=" PUB_S
,
1484 DM_NAME_PARAM(&question
->qname
),
1485 (first_rr
!= mDNSNULL
) ? DNS_TYPE_STR(first_rr
->rrtype
) : DNS_TYPE_STR(question
->qtype
)));
1487 // add wildcard answer
1488 mDNSs32 now
= m
->timenow
;
1489 if (answer
->RecordType
!= kDNSRecordTypePacketNegative
&& cache_group
!= mDNSNULL
) {
1490 for (CacheRecord
*cache_record
= cache_group
->members
; cache_record
!= mDNSNULL
; cache_record
= cache_record
->next
) {
1491 ResourceRecord
* const rr
= &cache_record
->resrec
;
1492 mDNSBool cache_record_answers_question
= SameNameCacheRecordAnswersQuestion(cache_record
, question
);
1493 if (!cache_record_answers_question
) {
1497 ssize_t remaining_ttl
= (size_t)rr
->rroriginalttl
- (now
- cache_record
->TimeRcvd
) / mDNSPlatformOneSecond
;
1498 if (remaining_ttl
<= 0) {
1499 log_default("Ignoring record: name="PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, remaining_ttl=%zd, rdlength=%d",
1500 DM_NAME_PARAM(rr
->name
), DNSTypeName(rr
->rrtype
), rr
->rroriginalttl
, remaining_ttl
, rr
->rdlength
);
1503 log_default("[R%u->Q%u] Adding record: name="PRI_DM_NAME
", rr_type=" PUB_S
", original_ttl=%d, remaining_ttl=%zd, rdlength=%d",
1504 request_id
, question_id
,
1505 DM_NAME_PARAM(rr
->name
), DNSTypeName(rr
->rrtype
), rr
->rroriginalttl
, remaining_ttl
, rr
->rdlength
);
1507 error
= add_to_originals_with_rrsig_t(&original
->original_result_with_rrsig
, rr
, !question
->InitialCacheMiss
, dns_result_error
, add_record
);
1508 require_action_quiet(error
== mStatus_NoError
, exit
, result
= dnssec_retrieval_record_not_added
);
1512 result
= suppressed
? dnssec_retrieval_suppressed
: dnssec_retrieval_no_error
;
1518 //======================================================================================================================
1520 //======================================================================================================================
1522 //======================================================================================================================
1523 // determine_response_type
1524 //======================================================================================================================
1526 mDNSlocal response_type_t
1527 determine_response_type(mDNSu16 rr_type
, const mDNSu8
* const _Nullable rdata
, const mDNSu16 question_type
) {
1528 response_type_t response_type
= unknown_response
;
1531 case kDNSType_CNAME
:
1532 if (question_type
!= kDNSType_CNAME
) response_type
= cname_response
;
1533 else response_type
= original_response
;
1536 verify(rr_type
== question_type
);
1537 response_type
= original_response
;
1539 case kDNSType_RRSIG
: {
1540 dns_type_rrsig_t
* rrsig_rdata
= (dns_type_rrsig_t
*)rdata
;
1541 mDNSu16 type_covered
= ntohs(rrsig_rdata
->type_covered
);
1542 require_action(type_covered
!= kDNSType_RRSIG
, exit
, response_type
= unknown_response
; log_error("Malformed RRSIG that covers RRSIG;"));
1543 response_type
= determine_response_type(type_covered
, mDNSNULL
, question_type
);
1547 response_type
= nsec_response
;
1549 case kDNSType_DNSKEY
:
1550 verify(rr_type
== question_type
);
1551 response_type
= original_response
;
1553 case kDNSType_NSEC3
:
1554 response_type
= nsec3_response
;
1557 if (rr_type
== question_type
) {
1558 response_type
= original_response
;
1560 response_type
= unknown_response
;
1566 return response_type
;
1569 //======================================================================================================================
1570 // domain_name_end_with
1571 //======================================================================================================================
1574 domain_name_end_with(const mDNSu8
* const _Nonnull longer
, const mDNSu8
* const _Nonnull shorter
) {
1575 mDNSu32 longer_length
= DOMAIN_NAME_LENGTH(longer
);
1576 mDNSu32 shorter_length
= DOMAIN_NAME_LENGTH(shorter
);
1577 const mDNSu8
*longer_ptr
;
1578 const mDNSu8
*shorter_ptr
;
1580 if (longer_length
< shorter_length
) {
1584 longer_ptr
= longer
+ longer_length
- 1;
1585 shorter_ptr
= shorter
+ shorter_length
- 1;
1587 for (mDNSu32 limit
= shorter_length
; limit
> 0; limit
--, longer_ptr
--, shorter_ptr
--) {
1588 if (*longer_ptr
!= *shorter_ptr
) {
1596 //======================================================================================================================
1597 // get_parent_zone_name
1598 //======================================================================================================================
1600 mDNSlocal
const mDNSu8
* _Nullable
1601 get_parent_zone_name(const list_t
* const _Nonnull zones
, originals_with_rrsig_t
* const _Nonnull original
) {
1602 const list_t
* rrsig_records
= mDNSNULL
;
1603 const dnssec_rrsig_t
* rrsig
= mDNSNULL
;
1604 const mDNSu8
* parent_zone_name
= mDNSNULL
;
1606 if (list_empty(zones
)) {
1607 switch (original
->type
) {
1608 case original_response
:
1609 rrsig_records
= &original
->u
.original
.rrsig_records
;
1611 case cname_response
:
1612 rrsig_records
= &original
->u
.cname_with_rrsig
.rrsig_records
;
1614 case nsec_response
: {
1615 const list_t
* const nsec_list
= &original
->u
.nsecs_with_rrsig
.nsec_and_rrsigs_same_name
;
1616 const one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
*)list_get_first(nsec_list
)->data
;
1617 rrsig_records
= &one_nsec
->rrsig_records
;
1618 verify_action(nsec_nsec3_contains_rrsigs_with_same_signer(nsec_list
, kDNSType_NSEC
), return mDNSNULL
);
1621 case nsec3_response
: {
1622 const list_t
* const nsec3_list
= &original
->u
.nsec3s_with_rrsig
.nsec3_and_rrsigs_same_name
;
1623 const one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
*)list_get_first(nsec3_list
)->data
;
1624 rrsig_records
= &one_nsec3
->rrsig_records
;
1625 verify_action(nsec_nsec3_contains_rrsigs_with_same_signer(nsec3_list
, kDNSType_NSEC3
), return mDNSNULL
);
1632 if (rrsig_records
!= mDNSNULL
&& !list_empty(rrsig_records
)) {
1633 rrsig
= (dnssec_rrsig_t
*)list_get_first(rrsig_records
)->data
;
1637 dnssec_zone_t
* last_zone
= (dnssec_zone_t
*)(list_get_last(zones
)->data
);
1638 dses_with_rrsig_t
* dses_with_rrsig
= &last_zone
->dses_with_rrsig
;
1640 if (last_zone
->dses_initialized
) {
1641 switch (dses_with_rrsig
->type
) {
1642 case original_response
:
1643 rrsig_records
= &dses_with_rrsig
->u
.original
.rrsig_records
;
1645 case nsec_response
: {
1646 const list_t
* const nsec_list
= &dses_with_rrsig
->u
.nsecs_with_rrsig
.nsec_and_rrsigs_same_name
;
1647 const one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
*)list_get_first(nsec_list
)->data
;
1648 rrsig_records
= &one_nsec
->rrsig_records
;
1651 case nsec3_response
: {
1652 const list_t
* const nsec3_list
= &dses_with_rrsig
->u
.nsec3s_with_rrsig
.nsec3_and_rrsigs_same_name
;
1653 const one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
*)list_get_first(nsec3_list
)->data
;
1654 rrsig_records
= &one_nsec3
->rrsig_records
;
1662 if (rrsig_records
!= mDNSNULL
&& !list_empty(rrsig_records
)) {
1663 rrsig
= (dnssec_rrsig_t
*)list_get_first(rrsig_records
)->data
;
1667 if (rrsig
!= mDNSNULL
&& domain_name_end_with(rrsig
->dnssec_rr
.name
.c
, rrsig
->signer_name
)) {
1668 parent_zone_name
= rrsig
->signer_name
;
1671 return parent_zone_name
;
1674 //======================================================================================================================
1675 // nsec_nsec3_contains_rrsigs_with_same_signer
1676 //======================================================================================================================
1679 nsec_nsec3_contains_rrsigs_with_same_signer(const list_t
* const nsec_nsec3_list
, mDNSu16 type
)
1681 mDNSBool contains_the_same_signer
= mDNSfalse
;
1682 const list_t
* first_rrsig_list
= mDNSNULL
;
1683 const dnssec_rrsig_t
* first_rrsig
= mDNSNULL
;
1684 const mDNSu8
* signer_name
= mDNSNULL
;
1686 require_action_quiet(type
== kDNSType_NSEC
|| type
== kDNSType_NSEC3
, exit
, contains_the_same_signer
= mDNSfalse
;
1687 log_debug("NSEC/NSEC3 list contains records other than NSEC/NSEC3 - Type: " PUB_S
, DNSTypeName(type
)));
1689 require_action_quiet(!list_empty(nsec_nsec3_list
), exit
, contains_the_same_signer
= mDNSfalse
;
1690 log_debug("NSEC/NSEC3 list is empty, which should never happens"));
1692 if (type
== kDNSType_NSEC
) {
1693 const one_nsec_with_rrsigs_t
* const first_one_nsec
= (one_nsec_with_rrsigs_t
* )(list_get_first(nsec_nsec3_list
)->data
);
1694 first_rrsig_list
= &first_one_nsec
->rrsig_records
;
1696 // type == kDNSType_NSEC3
1697 const one_nsec3_with_rrsigs_t
* const first_one_nsec3
= (one_nsec3_with_rrsigs_t
* )(list_get_first(nsec_nsec3_list
)->data
);
1698 first_rrsig_list
= &first_one_nsec3
->rrsig_records
;
1701 require_action_quiet(!list_empty(first_rrsig_list
), exit
, contains_the_same_signer
= mDNSfalse
;
1702 log_debug("The RRSIG list of " PUB_S
" is empty, such record should never be added into the list",
1703 DNSTypeName(type
)));
1705 first_rrsig
= (dnssec_rrsig_t
*)(list_get_first(first_rrsig_list
)->data
);
1706 signer_name
= first_rrsig
->signer_name
;
1708 for (const list_node_t
* one_nsec_nsec3_node
= list_get_first(nsec_nsec3_list
);
1709 !list_has_ended(nsec_nsec3_list
, one_nsec_nsec3_node
);
1710 one_nsec_nsec3_node
= list_next(one_nsec_nsec3_node
)) {
1712 const list_t
* rrsig_list
= mDNSNULL
;
1713 if (type
== kDNSType_NSEC
) {
1714 const one_nsec_with_rrsigs_t
* const one_nsec
= (one_nsec_with_rrsigs_t
*)one_nsec_nsec3_node
->data
;
1715 rrsig_list
= &one_nsec
->rrsig_records
;
1716 } else { // type == kDNSType_NSEC3
1717 const one_nsec3_with_rrsigs_t
* const one_nsec3
= (one_nsec3_with_rrsigs_t
*)one_nsec_nsec3_node
->data
;
1718 rrsig_list
= &one_nsec3
->rrsig_records
;
1721 for (const list_node_t
* rrsig_node
= list_get_first(rrsig_list
);
1722 !list_has_ended(rrsig_list
, rrsig_node
);
1723 rrsig_node
= list_next(rrsig_node
)) {
1725 const dnssec_rrsig_t
* const dnssec_rrsig
= (dnssec_rrsig_t
*)(rrsig_node
->data
);
1726 const mDNSu8
* const signer_name_to_compare
= dnssec_rrsig
->signer_name
;
1728 require_action_quiet(DOMAIN_NAME_EQUALS(signer_name
, signer_name_to_compare
), exit
,
1729 contains_the_same_signer
= mDNSfalse
;
1730 log_debug("RRSIGs do not have the same signer name - Signer name 1: " PRI_DM_NAME
", Signer name 2: " PRI_DM_NAME
,
1731 DM_NAME_PARAM((domainname
*)signer_name
), DM_NAME_PARAM((domainname
*)signer_name_to_compare
))
1736 contains_the_same_signer
= mDNStrue
;
1738 return contains_the_same_signer
;
1741 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)