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
initialize_dnssec_status_t(dnssec_status_t * const _Nonnull status,const domainname * const _Nonnull qname,const mDNSu16 qtype,const mDNSu32 flags,void * const _Nonnull context)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
uninitialize_dnssec_status_t(dnssec_status_t * const _Nonnull __unused status)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
create_dnssec_context_t(QueryRecordClientRequest * const _Nullable request,const mDNSu32 request_id,const domainname * const _Nonnull question_name,const mDNSu16 question_type,const mDNSu16 question_class,const mDNSInterfaceID _Nullable interface_id,const mDNSs32 service_id,const mDNSu32 flags,const mDNSBool append_search_domains,const mDNSs32 pid,const mDNSu8 * _Nullable uuid,const mDNSs32 uid,const audit_token_t * _Nullable peer_audit_token_ptr,const audit_token_t * _Nullable delegate_audit_token_ptr,const mDNSu8 * _Nullable resolver_uuid,mDNSBool need_encryption,const mdns_dns_service_id_t custom_id,const QueryRecordResultHandler _Nonnull result_handler,void * const _Nullable result_context,dnssec_context_t * const _Nullable primary_dnssec_context,dnssec_context_t * _Nullable * const _Nonnull out_dnssec_context)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
print_dnssec_context_t(const dnssec_context_t * const _Nonnull context)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
destroy_dnssec_context_t(dnssec_context_t * const _Nonnull context)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
add_no_error_records(mDNS * const _Nonnull m,DNSQuestion * _Nonnull question,const ResourceRecord * const _Nonnull answer,const QC_result add_record,const DNSServiceErrorType dns_result_error,dnssec_context_t * const _Nonnull dnssec_context)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
is_response_for_original_request(const original_t * const _Nonnull original,const DNSQuestion * const _Nonnull question)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
add_denial_of_existence_records(const mDNS * const _Nonnull m,const DNSQuestion * _Nonnull question,ResourceRecord * const _Nonnull answer,const QC_result add_record,const DNSServiceErrorType dns_result_error,dnssec_context_t * const _Nonnull dnssec_context)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
fetch_necessary_dnssec_records(dnssec_context_t * const _Nonnull context,mDNSBool anchor_reached)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
find_dnssec_zone_t(const list_t * const _Nonnull zones,const mDNSu8 * const _Nonnull name)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
add_to_cname_with_rrsig_t(cnames_with_rrsig_t * const _Nonnull cnames_with_rrisg,ResourceRecord * const _Nonnull rr)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
add_to_nsec_with_rrsig_t(nsecs_with_rrsig_t * const _Nonnull nsecs_with_rrisg,ResourceRecord * const _Nonnull rr)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
add_to_nsec3_with_rrsig_t(nsec3s_with_rrsig_t * const _Nonnull nsec3s_with_rrisg,ResourceRecord * const _Nonnull rr)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
add_to_originals_with_rrsig_t(originals_with_rrsig_t * const _Nonnull originals_with_rrisg,ResourceRecord * const _Nonnull rr,const mDNSBool answer_from_cache,const DNSServiceErrorType dns_error,const QC_result qc_result)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
add_to_dnskeys_with_rrsig_t(dnskeys_with_rrsig_t * const _Nonnull dnskeys_with_rrsig,ResourceRecord * const _Nonnull rr)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
add_to_dses_with_rrsig_t(dses_with_rrsig_t * const _Nonnull dses_with_rrsig,ResourceRecord * const _Nonnull rr)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
create_denial_of_existence_records_t(void)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
destroy_denial_of_existence_records_t(denial_of_existence_records_t * const _Nonnull denial_of_existence_records)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
destroy_denial_of_existence_records_t_if_nonnull(denial_of_existence_records_t * const _Nonnull 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) {
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
add_to_denial_of_existence_records_t(denial_of_existence_records_t * const _Nonnull denial_of_existence_records,const ResourceRecord * const _Nonnull rr)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
add_to_dnssec_zone_t(dnssec_zone_t * const _Nonnull zone,ResourceRecord * const _Nonnull rr,const mDNSu16 question_type)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
update_dnssec_zone_t_from_cache_for_no_error_response(const mDNS * const _Nonnull m,const DNSQuestion * const _Nonnull question,const ResourceRecord * const _Nonnull answer,const QC_result add_record,dnssec_zone_t * const _Nonnull zone)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
get_time_received_for_answer(const CacheGroup * const _Nonnull cache_group,const ResourceRecord * const _Nonnull answer)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
update_original_from_cache_for_no_error_response(mDNS * const _Nonnull m,const DNSQuestion * const _Nonnull question,const ResourceRecord * const _Nonnull answer,const QC_result add_record,const DNSServiceErrorType dns_result_error,dnssec_context_t * const _Nonnull dnssec_context)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
get_updated_type_from_answer(const ResourceRecord * const _Nonnull answer)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
update_original_from_cache_for_denial_of_existence_response(const mDNS * const _Nonnull m,const DNSQuestion * _Nonnull question,ResourceRecord * const _Nonnull answer,const QC_result add_record,const DNSServiceErrorType dns_result_error,dnssec_context_t * const _Nonnull dnssec_context)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
determine_response_type(mDNSu16 rr_type,const mDNSu8 * const _Nullable rdata,const mDNSu16 question_type)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
domain_name_end_with(const mDNSu8 * const _Nonnull longer,const mDNSu8 * const _Nonnull shorter)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
get_parent_zone_name(const list_t * const _Nonnull zones,originals_with_rrsig_t * const _Nonnull original)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
nsec_nsec3_contains_rrsigs_with_same_signer(const list_t * const nsec_nsec3_list,mDNSu16 type)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)
1742