]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/dnssec_v2/dnssec_v2_retrieval.c
mDNSResponder-1310.80.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / dnssec_v2 / dnssec_v2_retrieval.c
1 //
2 // dnssec_v2_retrieval.c
3 // mDNSResponder
4 //
5 // Copyright (c) 2020 Apple Inc. All rights reserved.
6 //
7
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"
17
18
19 //======================================================================================================================
20 // local functions prototypes
21 //======================================================================================================================
22
23 mDNSlocal response_type_t
24 determine_response_type(mDNSu16 rr_type, const mDNSu8 * const _Nullable rdata, const mDNSu16 question_type);
25
26 mDNSlocal mDNSBool
27 domain_name_end_with(const mDNSu8 * const _Nonnull longer, const mDNSu8 * const _Nonnull shorter);
28
29 mDNSlocal const mDNSu8 * _Nullable
30 get_parent_zone_name(const list_t * const _Nonnull zones, originals_with_rrsig_t * const _Nonnull original);
31
32 mDNSlocal mDNSBool
33 nsec_nsec3_contains_rrsigs_with_same_signer(const list_t * const nsec_nsec3_list, mDNSu16 type);
34
35 //======================================================================================================================
36 // functions
37 //======================================================================================================================
38
39 //======================================================================================================================
40 // initialize_dnssec_status_t
41 //======================================================================================================================
42
43 mDNSexport mStatus
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) {
46
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);
50
51 if (enable_dnssec) {
52 status->enable_dnssec = mDNStrue;
53 status->tried_dnssec_but_unsigned = mDNSfalse;
54 status->context = context;
55 } else {
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;
60 }
61
62 return mStatus_NoError;
63 }
64
65 //======================================================================================================================
66 // uninitialize_dnssec_status_t
67 //======================================================================================================================
68
69 mDNSexport mStatus
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;
75 }
76
77 #pragma mark - dnssec_context_t functions
78
79
80
81 #pragma mark create_dnssec_context_t
82 mDNSexport mStatus
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,
91 const mDNSu32 flags,
92 const mDNSBool append_search_domains,
93 const mDNSs32 pid,
94 const mDNSu8 * _Nullable uuid,
95 const mDNSs32 uid,
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,
99 #endif
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,
104 #endif
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) {
109
110 mStatus error = mStatus_NoError;
111 dnssec_context_t * context = mDNSNULL;
112 mDNSBool context_created = mDNSfalse;
113 original_request_parameters_t *parameters;
114
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;
118
119 context->me = request;
120
121 list_init(&context->zone_chain, sizeof(dnssec_zone_t));
122
123 // initialize original request fields
124 original_t * const original = &context->original;
125 original->original_result_with_rrsig.type = unknown_response;
126
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(&parameters->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);
140 } else {
141 uuid_clear(parameters->uuid);
142 }
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;
148 } else {
149 parameters->has_peer_audit_token = mDNSfalse;
150 }
151 if (delegate_audit_token_ptr != mDNSNULL) {
152 parameters->delegate_audit_token = *delegate_audit_token_ptr;
153 parameters->has_delegate_audit_token = mDNStrue;
154 } else {
155 parameters->has_delegate_audit_token = mDNSfalse;
156 }
157 #endif
158 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
159 if (resolver_uuid != mDNSNULL) {
160 uuid_copy(parameters->resolver_uuid, resolver_uuid);
161 } else {
162 uuid_clear(parameters->resolver_uuid);
163 }
164 parameters->need_encryption = need_encryption;
165 parameters->custom_id = custom_id;
166 #endif
167 parameters->user_handler = result_handler;
168 parameters->user_context = result_context;
169
170 original->original_trust_anchor = mDNSNULL;
171 original->last_time_add = INT_MIN;
172 original->last_time_rmv = INT_MIN;
173
174 // initialize returned_answers_t
175 initialize_returned_answers_t(&context->returned_answers, dnssec_indeterminate, kDNSServiceErr_Invalid);
176
177 // initialize denial of existence fields
178 context->denial_of_existence_records = mDNSNULL;
179
180 context->primary_dnssec_context = primary_dnssec_context;
181 context->subtask_dnssec_context = mDNSNULL;
182
183 *out_dnssec_context = context;
184
185 exit:
186 if (error != mStatus_NoError && context_created) free(context);
187 return error;
188 }
189
190 #pragma mark print_dnssec_context_t
191 mDNSexport void
192 print_dnssec_context_t(const dnssec_context_t * const _Nonnull context) {
193 mDNSu8 num_of_tabs = 0;
194
195 log_debug("\n");
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));
199
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));
203
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);
210 }
211
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));
215 log_debug("\n");
216 }
217
218 #pragma mark destroy_dnssec_context_t
219 mDNSexport void
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);
223 free(context);
224 }
225
226 #pragma mark - add_no_error_records
227
228 mDNSlocal mDNSBool
229 is_response_for_original_request(
230 const original_t * const _Nonnull original,
231 const DNSQuestion * const _Nonnull question);
232
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) {
241
242 dnssec_retrieval_result_t result;
243
244 dnssec_zone_t * const zone = find_dnssec_zone_t(&dnssec_context->zone_chain, question->qname.c);
245
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,
249 dnssec_context);
250 require_quiet(result == dnssec_retrieval_no_error, exit);
251 }
252
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);
258 }
259
260 result = dnssec_retrieval_no_error;
261 exit:
262 return result;
263 }
264
265 #pragma mark is_response_for_original_request
266 mDNSlocal mDNSBool
267 is_response_for_original_request(
268 const original_t * const _Nonnull original,
269 const DNSQuestion * const _Nonnull question) {
270
271 mDNSBool is_original_request = mDNSfalse;
272 const original_request_parameters_t * const parameters = &original->original_parameters;
273
274 if (parameters->question_name_hash != question->qnamehash) {
275 goto exit;
276 }
277
278 if (parameters->question_type != question->qtype) {
279 goto exit;
280 }
281
282 if (parameters->question_class != question->qclass) {
283 goto exit;
284 }
285
286 if (!DOMAIN_NAME_EQUALS(parameters->question_name.c, question->qname.c)) {
287 goto exit;
288 }
289
290 is_original_request = mDNStrue;
291 exit:
292 return is_original_request;
293 }
294
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) {
304
305 dnssec_retrieval_result_t result;
306
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);
310 } else {
311 result = dnssec_retrieval_non_dnskey_ds_record_for_zone;
312 goto exit;
313 }
314
315 exit:
316 return result;
317 }
318
319 //======================================================================================================================
320 // fetch_necessary_dnssec_records
321 //======================================================================================================================
322
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;
334
335 zone = list_empty(zones) ? mDNSNULL : (dnssec_zone_t *)list_get_last(zones)->data;
336
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);
339
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);
344
345 require_action(list_count_node(zones) < MAX_ZONES_ALLOWED, exit, retrieval_result = dnssec_retrieval_too_many_zones);
346
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)));
350
351 initialize_dnssec_zone_t(zone, parent_zone_name);
352
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;
360 } else {
361 zone->dnskey_request_started = mDNStrue;
362 zone->ds_request_started = mDNStrue;
363 }
364
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 ? &params->peer_audit_token : mDNSNULL,
372 params->has_delegate_audit_token ? &params->delegate_audit_token : mDNSNULL,
373 #endif
374 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
375 params->resolver_uuid, params->need_encryption, params->custom_id,
376 #endif
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)));
380 }
381
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 ? &params->peer_audit_token : mDNSNULL,
389 params->has_delegate_audit_token ? &params->delegate_audit_token : mDNSNULL,
390 #endif
391 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
392 params->resolver_uuid, params->need_encryption, params->custom_id,
393 #endif
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)));
397 }
398 } else {
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));
402
403 zone->trust_anchor = mDNSNULL;
404
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 ? &params->peer_audit_token : mDNSNULL,
412 params->has_delegate_audit_token ? &params->peer_audit_token : mDNSNULL,
413 #endif
414 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
415 params->resolver_uuid, params->need_encryption, params->custom_id,
416 #endif
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;
421 }
422
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 ? &params->peer_audit_token : mDNSNULL,
430 params->has_delegate_audit_token ? &params->delegate_audit_token : mDNSNULL,
431 #endif
432 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
433 params->resolver_uuid, params->need_encryption, params->custom_id,
434 #endif
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;
439 }
440 }
441
442 exit:
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
447 }
448 uninitialize_dnssec_zone_t(zone);
449 list_delete_node_with_data_ptr(zones, (void *)zone);
450 }
451 }
452
453 return retrieval_result;
454 }
455
456 //======================================================================================================================
457 // find_dnssec_zone_t
458 //======================================================================================================================
459
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)) {
465 return zone;
466 }
467 }
468
469 return mDNSNULL;
470 }
471
472 //======================================================================================================================
473 // add_to_cname_with_rrsig_t
474 //======================================================================================================================
475
476 mDNSexport mStatus
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;
483
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)));
487
488 initialize_dnssec_cname_t(cname, rr);
489 } else {
490 mDNSBool is_rrsig_valid = mDNSfalse;
491
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)));
495
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"));
499 }
500
501 exit:
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);
505 }
506 return error;
507 }
508
509 //======================================================================================================================
510 // add_to_nsec_with_rrsig_t
511 //======================================================================================================================
512
513 mDNSexport mStatus
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;
522
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;
532
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))
537 );
538
539 } else {
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"));
542
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;
546
547 if (name_hash_to_compare != name_hash || !DOMAIN_NAME_EQUALS(owner_name_to_compare, owner_name)) {
548 continue;
549 }
550
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;
557 }
558 }
559
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;"));
563
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))
568 );
569
570 error = mStatus_NoError;
571 insert_nsec_exit:
572 if (error != mStatus_NoError) {
573 if (new_one_nsec != mDNSNULL) {
574 list_delete_node_with_data_ptr(nsec_list, new_one_nsec);
575 }
576 }
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;
581
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;
586
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;
594 } else {
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;
598 }
599
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;
602 break;
603 }
604 }
605
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;"));
610
611 new_one_nsec->owner_name = mDNSNULL;
612 list_init(&new_one_nsec->rrsig_records, sizeof(dnssec_rrsig_t));
613
614 list_to_insert = &new_one_nsec->rrsig_records;
615 }
616
617 // insert new rrsig
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;"));
620
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"));
624
625 insert_rrsig_exit:
626 if (error != mStatus_NoError) {
627 if (new_rrsig != mDNSNULL) {
628 list_delete_node_with_data_ptr(list_to_insert, new_rrsig);
629 }
630 if (new_one_nsec != mDNSNULL) {
631 list_delete_node_with_data_ptr(nsec_list, new_one_nsec);
632 }
633 }
634 } else {
635 if (rr->rrtype != kDNSType_RRSIG) {
636 // wildcard
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;"));
640
641 initialize_dnssec_rr_t(dnssec_rr, rr);
642 } else {
643 // RRSIG
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;"));
647
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"));
651
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);
656 }
657 }
658 }
659 }
660
661 exit:
662 return error;
663 }
664
665 //======================================================================================================================
666 // add_to_nsec3_with_rrsig_t
667 //======================================================================================================================
668
669 mDNSexport mStatus
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;
678
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;
686
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))
691 );
692 } else {
693 require_action(!list_empty(&one_nsec3->rrsig_records), exit, error = mStatus_Invalid;
694 log_error("empty one_nsec3_with_rrsigs_t created"));
695
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;
699
700 if (name_hash_to_compare != name_hash || !DOMAIN_NAME_EQUALS(owner_name_to_compare, owner_name)) {
701 continue;
702 }
703
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;
710 }
711 }
712
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;"));
716
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))
721 );
722
723 insert_nsec3_exit:
724 if (error != mStatus_NoError) {
725 if (new_one_nsec3 != mDNSNULL) {
726 list_delete_node_with_data_ptr(nsec3_list, new_one_nsec3);
727 }
728 }
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;
733
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;
736
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;
744 } else {
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;
748 }
749
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;
752 }
753 }
754
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"));
759
760 new_one_nsec3->owner_name = mDNSNULL;
761 list_init(&new_one_nsec3->rrsig_records, sizeof(dnssec_rrsig_t));
762
763 list_to_insert = &new_one_nsec3->rrsig_records;
764 }
765
766 // insert new rrsig
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;"));
769
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"));
773
774 insert_rrsig_exit:
775 if (error != mStatus_NoError) {
776 if (new_rrsig != mDNSNULL) {
777 list_delete_node_with_data_ptr(list_to_insert, new_rrsig);
778 }
779 if (new_one_nsec3 != mDNSNULL) {
780 list_delete_node_with_data_ptr(nsec3_list, new_one_nsec3);
781 }
782 }
783 } else {
784 if (rr->rrtype != kDNSType_RRSIG) {
785 // wildcard
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;"));
789
790 initialize_dnssec_rr_t(dnssec_rr, rr);
791 } else {
792 // RRSIG
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;"));
796
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"));
800
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);
805 }
806 }
807 }
808 }
809
810 exit:
811 return error;
812 }
813
814 //======================================================================================================================
815 // add_to_originals_with_rrsig_t
816 //======================================================================================================================
817
818 mDNSexport mStatus
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) {
825
826 mStatus error = mStatus_NoError;
827
828 if (originals_with_rrisg->type == original_response) {
829 dnssec_rrsig_t * rrsig = mDNSNULL;
830 dnssec_original_t * original = mDNSNULL;
831
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)));
836
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"));
840 } else {
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)));
843
844 initialize_dnssec_original_t(original, rr, answer_from_cache, dns_error, qc_result);
845 }
846
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);
851 goto exit;
852 }
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)));
862 } else {
863 verify(mDNSfalse);
864 }
865
866 exit:
867 return error;
868 }
869
870 //======================================================================================================================
871 // dnskeys_with_rrsig_t functions
872 //======================================================================================================================
873
874 //======================================================================================================================
875 // add_to_dnskeys_with_rrsig_t
876 //======================================================================================================================
877
878 mDNSexport mStatus
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;
883
884 dnssec_dnskey_t * dnskey = mDNSNULL;
885 dnssec_rrsig_t * rrsig = mDNSNULL;
886
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)));
890
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"));
894 } else {
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)));
898
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"));
902 }
903
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);
908 }
909 return error;
910 }
911
912 //======================================================================================================================
913 // add_to_dses_with_rrsig_t
914 //======================================================================================================================
915
916 mDNSexport mStatus
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;
920
921 if (dses_with_rrsig->type == original_response) {
922 dnssec_ds_t * ds = mDNSNULL;
923 dnssec_rrsig_t *rrsig = mDNSNULL;
924
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)));
928
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"));
932 } else {
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)));
936
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"));
940 }
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);
945 goto exit;
946 }
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)));
953 } else{
954 error = mStatus_Invalid;
955 log_error("invalid response type for DS record");
956 }
957
958 exit:
959 return error;
960 }
961
962 //======================================================================================================================
963 // initialize_denial_of_existence_records_t
964 //======================================================================================================================
965
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);
970
971 list_init(&denial->resource_records, sizeof(ResourceRecord));
972
973 exit:
974 return denial;
975 }
976
977 //======================================================================================================================
978 // destroy_denial_of_existence_records_t
979 //======================================================================================================================
980
981 mDNSexport void
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);
987 }
988 list_uninit(denial_rrs);
989 free(denial_of_existence_records);
990 }
991
992 mDNSexport void
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) {
995 return;
996 }
997
998 destroy_denial_of_existence_records_t(denial_of_existence_records);
999 }
1000
1001 //======================================================================================================================
1002 // add_to_denial_of_existence_records_t
1003 //======================================================================================================================
1004
1005 mDNSexport mStatus
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;
1010
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)));
1013
1014 error = deep_copy_resource_record(rr_copy, rr);
1015 require_action(error == mStatus_NoError, exit, log_error("initialize_dnssec_rr_t failed"));
1016
1017 exit:
1018 return error;
1019 }
1020
1021 //======================================================================================================================
1022 // add_to_dnssec_zone_t
1023 //======================================================================================================================
1024
1025 mDNSexport mStatus
1026 add_to_dnssec_zone_t(
1027 dnssec_zone_t * const _Nonnull zone,
1028 ResourceRecord * const _Nonnull rr,
1029 const mDNSu16 question_type) {
1030
1031 mStatus error = mStatus_NoError;
1032
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;
1044 }
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)));
1047 } else {
1048 error = mStatus_Invalid;
1049 log_error("Non DS/DNSKEY query created for dnssec zone; qtype=" PUB_S, DNS_TYPE_STR(question_type));
1050 }
1051
1052 exit:
1053 return error;
1054 }
1055
1056 #pragma mark - Update DNSSEC Records
1057
1058 #pragma mark - update_dnssec_zone_t_from_cache_for_no_error_response
1059
1060 mDNSlocal mDNSs32
1061 get_time_received_for_answer(
1062 const CacheGroup * const _Nonnull cache_group,
1063 const ResourceRecord * const _Nonnull answer);
1064
1065 mDNSlocal mDNSu16
1066 get_updated_type_from_answer(const ResourceRecord * const _Nonnull answer);
1067
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) {
1075
1076 dnssec_retrieval_result_t result = dnssec_retrieval_unknown_error;
1077 mStatus 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);
1084
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)));
1088
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)));
1093
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)));
1098
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)));
1104
1105 if (updated_type == kDNSType_DS) {
1106 require_action_quiet(zone->ds_request_started, exit, result = dnssec_retrieval_invalid_internal_state;);
1107
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));
1118 goto exit;
1119 } else {
1120 result = dnssec_retrieval_no_new_change;
1121 goto exit;
1122 }
1123 } else if (updated_type == kDNSType_DNSKEY) {
1124 require_action_quiet(zone->dnskey_request_started, exit, result = dnssec_retrieval_invalid_internal_state;);
1125
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));
1137 goto exit;
1138 } else {
1139 result = dnssec_retrieval_no_new_change;
1140 goto exit;
1141 }
1142 } else {
1143 result = dnssec_retrieval_non_dnskey_ds_record_for_zone;
1144 goto exit;
1145 }
1146
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) {
1153 continue;
1154 }
1155
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);
1160 continue;
1161 }
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);
1165
1166 error = add_to_dnssec_zone_t(zone, rr, question->qtype);
1167 require_action_quiet(error == mStatus_NoError, exit, result = dnssec_retrieval_unknown_error);
1168
1169 if (!new_record_added) {
1170 new_record_added = mDNStrue;
1171 }
1172 last_time_received = MAX(last_time_received, cache_record->TimeRcvd);
1173 }
1174
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)
1179 );
1180
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;
1186 }
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,
1191 add_record)
1192 );
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;
1198 }
1199 contains_rrsig = contains_rrsig_in_dnskeys_with_rrsig_t(&zone->dnskeys_with_rrsig);
1200 } else {
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));
1203 goto exit;
1204 }
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)));
1208
1209 result = dnssec_retrieval_no_error;
1210 exit:
1211 return result;
1212 }
1213
1214 #pragma mark get_time_received_for_answer
1215 mDNSlocal mDNSs32
1216 get_time_received_for_answer(
1217 const CacheGroup * const _Nonnull cache_group,
1218 const ResourceRecord * const _Nonnull answer) {
1219
1220 mDNSs32 last_time_received = 0;
1221
1222 for (CacheRecord *cache_record = cache_group->members; cache_record != mDNSNULL; cache_record = cache_record->next) {
1223 if (answer != &cache_record->resrec) {
1224 continue;
1225 }
1226
1227 last_time_received = cache_record->TimeRcvd;
1228 goto exit;
1229 }
1230
1231 exit:
1232 return last_time_received;
1233 }
1234
1235 #pragma mark - update_original_from_cache_for_no_error_response
1236
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) {
1245
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);
1254
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)));
1259
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)));
1264
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;
1268
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);
1272 }
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);
1279
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;
1284 goto exit;
1285 } else {
1286 result = dnssec_retrieval_no_new_change;
1287 goto exit;
1288 }
1289
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) {
1296 continue;
1297 }
1298
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);
1303 continue;
1304 }
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);
1308
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);
1316
1317 if (type == cname_response) {
1318 QueryRecordClientRequest * const primary_request = GET_PRIMARY_REQUEST(dnssec_context);
1319
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));
1323
1324 // increment the referrals.
1325 primary_request->op.q.CNAMEReferrals++;
1326 }
1327 }
1328
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;
1333 }
1334 last_time_received = MAX(last_time_received, cache_record->TimeRcvd);
1335 }
1336
1337 if (new_record_added) {
1338 original->last_time_add = last_time_received;
1339 }
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)));
1345
1346 result = dnssec_retrieval_no_error;
1347 exit:
1348 return result;
1349 }
1350
1351 #pragma mark get_updated_type_from_answer
1352 mDNSlocal mDNSu16
1353 get_updated_type_from_answer(const ResourceRecord * const _Nonnull answer) {
1354 mDNSu16 type = kDNSQType_ANY;
1355
1356 if (answer->rrtype == kDNSType_RRSIG) {
1357 type = get_covered_type_of_dns_type_rrsig_t(answer->rdata->u.data);
1358 } else {
1359 type = answer->rrtype;
1360 }
1361
1362 return type;
1363 }
1364
1365 #pragma mark - update_original_from_cache_for_denial_of_existence_response
1366
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) {
1375
1376 dnssec_retrieval_result_t result = dnssec_retrieval_unknown_error;
1377 mStatus 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;
1388
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);
1392 } else {
1393 denial_rrs = mDNSNULL;
1394 }
1395
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)));
1401
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)));
1407 } else {
1408 last_time_received = INT_MIN;
1409 }
1410
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
1413 // must be removed
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;
1418 }
1419 } else {
1420 result = dnssec_retrieval_no_new_change;
1421 goto exit;
1422 }
1423
1424 require_action_quiet(add_record == QC_add || suppressed,
1425 exit, result = dnssec_retrieval_invalid_internal_state);
1426
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)));
1433 } else {
1434 type = original_response;
1435 }
1436
1437 initialize_originals_with_rrsig_t(originals_with_rrsig, type);
1438
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;
1452 if (!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);
1456 } else {
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);
1461 }
1462 } else {
1463 result = dnssec_retrieval_invalid_internal_state;
1464 goto exit;
1465 }
1466
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;
1470
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);
1474
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);
1477 }
1478 }
1479
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)));
1486
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) {
1494 continue;
1495 }
1496
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);
1501 continue;
1502 }
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);
1506
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);
1509 }
1510 }
1511
1512 result = suppressed ? dnssec_retrieval_suppressed : dnssec_retrieval_no_error;
1513 exit:
1514 return result;
1515 }
1516
1517
1518 //======================================================================================================================
1519 // local function
1520 //======================================================================================================================
1521
1522 //======================================================================================================================
1523 // determine_response_type
1524 //======================================================================================================================
1525
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;
1529
1530 switch (rr_type) {
1531 case kDNSType_CNAME:
1532 if (question_type != kDNSType_CNAME) response_type = cname_response;
1533 else response_type = original_response;
1534 break;
1535 case kDNSType_DS:
1536 verify(rr_type == question_type);
1537 response_type = original_response;
1538 break;
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);
1544 }
1545 break;
1546 case kDNSType_NSEC:
1547 response_type = nsec_response;
1548 break;
1549 case kDNSType_DNSKEY:
1550 verify(rr_type == question_type);
1551 response_type = original_response;
1552 break;
1553 case kDNSType_NSEC3:
1554 response_type = nsec3_response;
1555 break;
1556 default:
1557 if (rr_type == question_type) {
1558 response_type = original_response;
1559 } else {
1560 response_type = unknown_response;
1561 }
1562 break;
1563 }
1564
1565 exit:
1566 return response_type;
1567 }
1568
1569 //======================================================================================================================
1570 // domain_name_end_with
1571 //======================================================================================================================
1572
1573 mDNSlocal mDNSBool
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;
1579
1580 if (longer_length < shorter_length) {
1581 return mDNSfalse;
1582 }
1583
1584 longer_ptr = longer + longer_length - 1;
1585 shorter_ptr = shorter + shorter_length - 1;
1586
1587 for (mDNSu32 limit = shorter_length; limit > 0; limit--, longer_ptr--, shorter_ptr--) {
1588 if (*longer_ptr != *shorter_ptr) {
1589 return mDNSfalse;
1590 }
1591 }
1592
1593 return mDNStrue;
1594 }
1595
1596 //======================================================================================================================
1597 // get_parent_zone_name
1598 //======================================================================================================================
1599
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;
1605
1606 if (list_empty(zones)) {
1607 switch (original->type) {
1608 case original_response:
1609 rrsig_records = &original->u.original.rrsig_records;
1610 break;
1611 case cname_response:
1612 rrsig_records = &original->u.cname_with_rrsig.rrsig_records;
1613 break;
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);
1619 break;
1620 }
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);
1626 break;
1627 }
1628 default:
1629 break;
1630 }
1631
1632 if (rrsig_records != mDNSNULL && !list_empty(rrsig_records)) {
1633 rrsig = (dnssec_rrsig_t *)list_get_first(rrsig_records)->data;
1634 }
1635
1636 } else {
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;
1639
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;
1644 break;
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;
1649 break;
1650 }
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;
1655 break;
1656 }
1657 default:
1658 break;
1659 }
1660 }
1661
1662 if (rrsig_records != mDNSNULL && !list_empty(rrsig_records)) {
1663 rrsig = (dnssec_rrsig_t *)list_get_first(rrsig_records)->data;
1664 }
1665 }
1666
1667 if (rrsig != mDNSNULL && domain_name_end_with(rrsig->dnssec_rr.name.c, rrsig->signer_name)) {
1668 parent_zone_name = rrsig->signer_name;
1669 }
1670
1671 return parent_zone_name;
1672 }
1673
1674 //======================================================================================================================
1675 // nsec_nsec3_contains_rrsigs_with_same_signer
1676 //======================================================================================================================
1677
1678 mDNSlocal mDNSBool
1679 nsec_nsec3_contains_rrsigs_with_same_signer(const list_t * const nsec_nsec3_list, mDNSu16 type)
1680 {
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;
1685
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)));
1688
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"));
1691
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;
1695 } else {
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;
1699 }
1700
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)));
1704
1705 first_rrsig = (dnssec_rrsig_t *)(list_get_first(first_rrsig_list)->data);
1706 signer_name = first_rrsig->signer_name;
1707
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)) {
1711
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;
1719 }
1720
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)) {
1724
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;
1727
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))
1732 );
1733 }
1734 }
1735
1736 contains_the_same_signer = mDNStrue;
1737 exit:
1738 return contains_the_same_signer;
1739 }
1740
1741 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)