]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/QuerierSupport.c
mDNSResponder-1310.80.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / QuerierSupport.c
1 /*
2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "QuerierSupport.h"
18
19 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
20 #include "DebugServices.h"
21 #include "dns_sd_internal.h"
22 #include "mDNSMacOSX.h"
23 #include "mdns_xpc.h"
24 #include "uDNS.h"
25
26 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
27 #include "Metrics.h"
28 #endif
29
30 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
31 #include "dnssec_v2.h"
32 #endif
33
34 #include <libproc.h>
35 #include <mach/mach_time.h>
36 #include "mdns_helpers.h"
37
38 int PQWorkaroundThreshold = 0;
39
40 extern mDNS mDNSStorage;
41
42 mDNSlocal void _Querier_LogDNSServices(const mdns_dns_service_manager_t manager)
43 {
44 __block mDNSu32 count = 0;
45 const mDNSu32 total = (mDNSu32)mdns_dns_service_manager_get_count(manager);
46 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Updated DNS services (%u)", total);
47 mdns_dns_service_manager_iterate(manager,
48 ^ bool (const mdns_dns_service_t service)
49 {
50 count++;
51 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "DNS service (%u/%u) -- %@", count, total, service);
52 return false;
53 });
54 }
55
56 mDNSexport mdns_dns_service_manager_t Querier_GetDNSServiceManager(void)
57 {
58 mDNS *const m = &mDNSStorage;
59 static mdns_dns_service_manager_t sDNSServiceManager = NULL;
60 if (sDNSServiceManager)
61 {
62 return sDNSServiceManager;
63 }
64 const mdns_dns_service_manager_t manager = mdns_dns_service_manager_create(dispatch_get_main_queue(), NULL);
65 if (!manager)
66 {
67 return NULL;
68 }
69 mdns_dns_service_manager_set_report_symptoms(manager, true);
70 mdns_dns_service_manager_enable_problematic_qtype_workaround(manager, PQWorkaroundThreshold);
71 mdns_dns_service_manager_set_event_handler(manager,
72 ^(mdns_event_t event, __unused OSStatus error)
73 {
74 KQueueLock();
75 switch (event)
76 {
77 case mdns_event_error:
78 mdns_dns_service_manager_invalidate(manager);
79 if (sDNSServiceManager == manager)
80 {
81 mdns_forget(&sDNSServiceManager);
82 }
83 break;
84
85 case mdns_event_update:
86 mdns_dns_service_manager_apply_pending_updates(manager);
87 mDNS_Lock(m);
88 Querier_ProcessDNSServiceChanges();
89 _Querier_LogDNSServices(manager);
90 mDNS_Unlock(m);
91 break;
92
93 case mdns_event_invalidated:
94 mdns_release(manager);
95 break;
96
97 default:
98 break;
99 }
100 KQueueUnlock("DNS Service Manager event handler");
101 });
102 sDNSServiceManager = manager;
103 mdns_retain(sDNSServiceManager);
104 mdns_dns_service_manager_activate(sDNSServiceManager);
105 return sDNSServiceManager;
106 }
107
108 mDNSlocal mdns_dns_service_t _Querier_GetDNSService(const DNSQuestion *q)
109 {
110 mdns_dns_service_t service;
111 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
112 if (!manager)
113 {
114 return NULL;
115 }
116 if (!uuid_is_null(q->ResolverUUID))
117 {
118 service = mdns_dns_service_manager_get_uuid_scoped_service(manager, q->ResolverUUID);
119 }
120 else if (q->InterfaceID)
121 {
122 const uint32_t ifIndex = (uint32_t)((uintptr_t)q->InterfaceID);
123 service = mdns_dns_service_manager_get_interface_scoped_service(manager, q->qname.c, ifIndex);
124 }
125 else if (q->ServiceID >= 0)
126 {
127 service = mdns_dns_service_manager_get_service_scoped_service(manager, q->qname.c, (uint32_t)q->ServiceID);
128 }
129 else
130 {
131 // Check for a matching discovered resolver for unscoped queries
132 uuid_t discoveredResolverUUID = {};
133 if (mdns_dns_service_manager_fillout_discovered_service_for_name(manager, q->qname.c, discoveredResolverUUID))
134 {
135 service = mdns_dns_service_manager_get_uuid_scoped_service(manager, discoveredResolverUUID);
136 }
137 else
138 {
139 service = mdns_dns_service_manager_get_unscoped_service(manager, q->qname.c);
140 }
141 }
142 if (service && !mdns_dns_service_interface_is_vpn(service))
143 {
144 // Check for encryption, and if the service isn't encrypted, fallback or fail
145 const mDNSBool lacksRequiredEncryption = q->RequireEncryption && !mdns_dns_service_is_encrypted(service);
146 if (lacksRequiredEncryption || mdns_dns_service_has_connection_problems(service))
147 {
148 if (lacksRequiredEncryption)
149 {
150 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
151 "[R%u->Q%u] DNS service %llu lacks required encryption",
152 q->request_id, mDNSVal16(q->TargetQID), mdns_dns_service_get_id(service));
153 service = NULL;
154 }
155
156 // Check for a fallback service
157 if (q->CustomID != 0)
158 {
159 service = mdns_dns_service_manager_get_custom_service(manager, q->CustomID);
160 }
161 }
162 }
163 return service;
164 }
165
166 mDNSlocal pid_t _Querier_GetMyPID(void)
167 {
168 static dispatch_once_t sOnce = 0;
169 static pid_t sPID = 0;
170 dispatch_once(&sOnce,
171 ^{
172 sPID = getpid();
173 });
174 return sPID;
175 }
176
177 mDNSlocal const mDNSu8 *_Querier_GetMyUUID(void)
178 {
179 static dispatch_once_t sOnce = 0;
180 static mDNSu8 sUUID[16];
181 dispatch_once(&sOnce,
182 ^{
183 uuid_clear(sUUID);
184 struct proc_uniqidentifierinfo info;
185 const int n = proc_pidinfo(_Querier_GetMyPID(), PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof(info));
186 if (n == (int)sizeof(info))
187 {
188 uuid_copy(sUUID, info.p_uuid);
189 }
190 });
191 return sUUID;
192 }
193
194 mDNSlocal mDNSBool _Querier_QuestionBelongsToSelf(const DNSQuestion *q)
195 {
196 if (q->pid != 0)
197 {
198 return ((q->pid == _Querier_GetMyPID()) ? mDNStrue : mDNSfalse);
199 }
200 else
201 {
202 return ((uuid_compare(q->uuid, _Querier_GetMyUUID()) == 0) ? mDNStrue : mDNSfalse);
203 }
204 }
205
206 mDNSlocal mDNSBool _Querier_DNSServiceIsUnscopedAndLacksPrivacy(const mdns_dns_service_t service)
207 {
208 if ((mdns_dns_service_get_scope(service) == mdns_dns_service_scope_none) &&
209 !mdns_dns_service_is_encrypted(service) && !mdns_dns_service_interface_is_vpn(service))
210 {
211 return mDNStrue;
212 }
213 else
214 {
215 return mDNSfalse;
216 }
217 }
218
219 #define kQuerierLogFullDNSServicePeriodSecs 30
220
221 mDNSlocal mDNSBool _Querier_ShouldLogFullDNSService(const mdns_dns_service_t service)
222 {
223 uint64_t *lastFullLogTicks = (uint64_t *)mdns_dns_service_get_context(service);
224 if (lastFullLogTicks)
225 {
226 const uint64_t nowTicks = mach_continuous_time();
227 const uint64_t diffTicks = nowTicks - *lastFullLogTicks;
228 if ((diffTicks / mdns_mach_ticks_per_second()) < kQuerierLogFullDNSServicePeriodSecs)
229 {
230 return mDNSfalse;
231 }
232 *lastFullLogTicks = nowTicks;
233 }
234 else
235 {
236 lastFullLogTicks = (uint64_t *)malloc(sizeof(*lastFullLogTicks));
237 if (lastFullLogTicks)
238 {
239 *lastFullLogTicks = mach_continuous_time();
240 mdns_dns_service_set_context(service, lastFullLogTicks);
241 mdns_dns_service_set_context_finalizer(service, free);
242 }
243 }
244 return mDNStrue;
245 }
246
247 mDNSexport void Querier_SetDNSServiceForQuestion(DNSQuestion *q)
248 {
249 // Thus far, UUID-scoped DNS services may be specified without any server IP addresses, just a hostname. In such a
250 // case, the underlying nw_connection will need to resolve the DNS service's hostname. To avoid potential dependency
251 // cycles because of mDNSResponder issuing GetAddrInfo requests to itself, we simply prevent DNSQuestions with
252 // mDNSResponder's PID or Mach-O UUID from using UUID-scoped DNS services.
253 if (!uuid_is_null(q->ResolverUUID) && _Querier_QuestionBelongsToSelf(q))
254 {
255 uuid_clear(q->ResolverUUID);
256 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
257 "[R%u->Q%u] Cleared resolver UUID for mDNSResponder's own question: " PRI_DM_NAME " (" PUB_S ")",
258 q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
259 }
260 mdns_forget(&q->dnsservice);
261 mDNSBool retryPathEval = mDNSfalse;
262 mdns_dns_service_t service = _Querier_GetDNSService(q);
263 if (service)
264 {
265 // If path evaluation for the original QNAME was done by the client, but a CNAME restart has lead us to use a
266 // DNS service that isn't identical to the previous DNS service, and the DNS service is unscoped and lacks
267 // privacy, then retry path evaluation. A path evaluation with the new QNAME may result in using a DNS service
268 // that offers privacy.
269 if ((q->flags & kDNSServiceFlagsPathEvaluationDone) &&
270 (q->lastDNSServiceID != 0) && (mdns_dns_service_get_id(service) != q->lastDNSServiceID) &&
271 _Querier_DNSServiceIsUnscopedAndLacksPrivacy(service))
272 {
273 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
274 "[R%u->Q%u] Retrying path evaluation for " PRI_DM_NAME " (" PUB_S ") to avoid non-private DNS service",
275 q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
276 retryPathEval = mDNStrue;
277 }
278 }
279 else if (!uuid_is_null(q->ResolverUUID))
280 {
281 // If the ResolverUUID is not null, but we didn't get a DNS service, then the ResolverUUID may be stale, i.e.,
282 // the resolver configuration with that UUID may have been deleted, so retry path evaluation.
283 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
284 "[R%u->Q%u] Retrying path evaluation for " PRI_DM_NAME " (" PUB_S ") because ResolverUUID may be stale",
285 q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype));
286 retryPathEval = mDNStrue;
287 }
288 if (retryPathEval)
289 {
290 mDNSPlatformGetDNSRoutePolicy(q);
291 service = _Querier_GetDNSService(q);
292 }
293 q->dnsservice = service;
294 mdns_retain_null_safe(q->dnsservice);
295 if (!q->dnsservice || _Querier_ShouldLogFullDNSService(q->dnsservice))
296 {
297 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
298 "[R%u->Q%u] Question for " PRI_DM_NAME " (" PUB_S ") assigned DNS service -- %@",
299 q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), q->dnsservice);
300 }
301 else
302 {
303 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
304 "[R%u->Q%u] Question for " PRI_DM_NAME " (" PUB_S ") assigned DNS service %llu",
305 q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype),
306 mdns_dns_service_get_id(q->dnsservice));
307 }
308 }
309
310 mDNSexport void Querier_RegisterPathResolver(const uuid_t resolverUUID)
311 {
312 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
313 if (manager)
314 {
315 mdns_dns_service_manager_register_path_resolver(manager, resolverUUID);
316 }
317 }
318
319 mDNSexport mdns_dns_service_id_t Querier_RegisterCustomDNSService(const xpc_object_t resolverConfigDict)
320 {
321 mdns_dns_service_id_t ident = 0;
322 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
323 if (manager)
324 {
325 ident = mdns_dns_service_manager_register_custom_service(manager, resolverConfigDict);
326 }
327 return ident;
328 }
329
330 mDNSexport mdns_dns_service_id_t Querier_RegisterCustomDNSServiceWithPListData(const uint8_t *dataPtr, size_t dataLen)
331 {
332 mdns_dns_service_id_t ident = 0;
333 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
334 if (manager)
335 {
336 xpc_object_t resolverConfigDict = mdns_xpc_create_dictionary_from_plist_data(dataPtr, dataLen, NULL);
337 if (resolverConfigDict)
338 {
339 ident = mdns_dns_service_manager_register_custom_service(manager, resolverConfigDict);
340 xpc_release(resolverConfigDict);
341 }
342 }
343 return ident;
344 }
345
346 mDNSexport void Querier_DeregisterCustomDNSService(const mdns_dns_service_id_t ident)
347 {
348 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
349 if (manager)
350 {
351 mdns_dns_service_manager_deregister_custom_service(manager, ident);
352 }
353 }
354
355 mDNSexport void Querier_RegisterDoHURI(const char *doh_uri, const char *domain)
356 {
357 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
358 if (manager)
359 {
360 mdns_dns_service_manager_register_doh_uri(manager, doh_uri, domain);
361 }
362 }
363
364 mDNSexport void Querier_ApplyDNSConfig(const dns_config_t *config)
365 {
366 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
367 if (manager)
368 {
369 mdns_dns_service_manager_apply_dns_config(manager, config);
370 _Querier_LogDNSServices(manager);
371 }
372 }
373
374 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
375 mDNSlocal void _Querier_UpdateQuestionMetrics(DNSQuestion *const q)
376 {
377 if (q->querier && (mdns_querier_get_resolver_type(q->querier) == mdns_resolver_type_normal))
378 {
379 q->metrics.querySendCount += mdns_querier_get_send_count(q->querier);
380 if (q->metrics.dnsOverTCPState == DNSOverTCP_None)
381 {
382 switch (mdns_querier_get_over_tcp_reason(q->querier))
383 {
384 case mdns_query_over_tcp_reason_truncation:
385 q->metrics.dnsOverTCPState = DNSOverTCP_Truncated;
386 break;
387
388 case mdns_query_over_tcp_reason_got_suspicious_reply:
389 q->metrics.dnsOverTCPState = DNSOverTCP_Suspicious;
390 break;
391
392 case mdns_query_over_tcp_reason_in_suspicious_mode:
393 q->metrics.dnsOverTCPState = DNSOverTCP_SuspiciousDefense;
394 break;
395
396 default:
397 break;
398 }
399 }
400 }
401 }
402
403 mDNSlocal void _Querier_UpdateDNSMessageSizeMetrics(const mdns_querier_t querier)
404 {
405 if (mdns_querier_get_resolver_type(querier) == mdns_resolver_type_normal)
406 {
407 if (mdns_querier_get_send_count(querier) > 0)
408 {
409 const mDNSu32 len = mdns_querier_get_query_length(querier);
410 if (len > 0)
411 {
412 MetricsUpdateDNSQuerySize(len);
413 }
414 }
415 if ((mdns_querier_get_result_type(querier) == mdns_querier_result_type_response) &&
416 !mdns_querier_response_is_fabricated(querier))
417 {
418 const mDNSu32 len = mdns_querier_get_response_length(querier);
419 if (len > 0)
420 {
421 MetricsUpdateDNSResponseSize(len);
422 }
423 }
424 }
425 }
426 #endif
427
428 mDNSlocal mdns_set_t _Querier_GetOrphanedQuerierSet(void)
429 {
430 static mdns_set_t sOrphanedQuerierSet = NULL;
431 if (!sOrphanedQuerierSet)
432 {
433 sOrphanedQuerierSet = mdns_set_create();
434 }
435 return sOrphanedQuerierSet;
436 }
437
438 mDNSlocal void _Querier_HandleQuerierResponse(const mdns_querier_t querier, const mdns_dns_service_t dnsservice)
439 {
440 KQueueLock();
441 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
442 "[Q%u] Handling concluded querier: %@", mdns_querier_get_user_id(querier), querier);
443 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
444 _Querier_UpdateDNSMessageSizeMetrics(querier);
445 #endif
446 const mdns_querier_result_type_t resultType = mdns_querier_get_result_type(querier);
447 if (resultType == mdns_querier_result_type_response)
448 {
449 mDNS *const m = &mDNSStorage;
450 if (!mdns_dns_service_is_defunct(dnsservice))
451 {
452 size_t copyLen = mdns_querier_get_response_length(querier);
453 if (copyLen > sizeof(m->imsg.m))
454 {
455 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
456 "[Q%u] Large %lu-byte response will be truncated to fit mDNSCore's %lu-byte message buffer",
457 mdns_querier_get_user_id(querier), (unsigned long)copyLen, (unsigned long)sizeof(m->imsg.m));
458 copyLen = sizeof(m->imsg.m);
459 }
460 memcpy(&m->imsg.m, mdns_querier_get_response_ptr(querier), copyLen);
461 const mDNSu8 *const end = ((mDNSu8 *)&m->imsg.m) + copyLen;
462 mDNSCoreReceiveForQuerier(m, &m->imsg.m, end, querier, dnsservice);
463 }
464 }
465 const mdns_set_t set = _Querier_GetOrphanedQuerierSet();
466 if (set)
467 {
468 mdns_set_remove(set, (uintptr_t)dnsservice, querier);
469 }
470 DNSQuestion *const q = Querier_GetDNSQuestion(querier);
471 if (q)
472 {
473 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
474 _Querier_UpdateQuestionMetrics(q);
475 #endif
476 mdns_forget(&q->querier);
477 // If the querier timed out, then the DNSQuestion was using an orphaned querier.
478 // Querier_HandleUnicastQuestion() will attempt to give it a new querier.
479 if (resultType == mdns_querier_result_type_timeout)
480 {
481 Querier_HandleUnicastQuestion(q);
482 }
483 else if (resultType == mdns_querier_result_type_error)
484 {
485 // The querier encountered a fatal error, which should be rare. There's nothing we can do but try again.
486 // This usually happens if there's resource exhaustion, so be conservative and wait five seconds before
487 // trying again.
488 mDNS *const m = &mDNSStorage;
489 q->ThisQInterval = 5 * mDNSPlatformOneSecond;
490 q->LastQTime = m->timenow;
491 SetNextQueryTime(m, q);
492 }
493 }
494 KQueueUnlock("_Querier_HandleQuerierResponse");
495 }
496
497 mDNSexport void Querier_HandleUnicastQuestion(DNSQuestion *q)
498 {
499 mDNS *const m = &mDNSStorage;
500 mdns_querier_t querier = NULL;
501 if (!q->dnsservice || q->querier) goto exit;
502
503 const mdns_set_t set = _Querier_GetOrphanedQuerierSet();
504 if (set)
505 {
506 __block mdns_querier_t orphan = NULL;
507 mdns_set_iterate(set, (uintptr_t)q->dnsservice,
508 ^ bool (mdns_object_t _Nonnull object)
509 {
510 const mdns_querier_t candidate = (mdns_querier_t)object;
511 if (mdns_querier_match(candidate, q->qname.c, q->qtype, q->qclass))
512 {
513 orphan = candidate;
514 return true;
515 }
516 else
517 {
518 return false;
519 }
520 });
521 if (orphan)
522 {
523 q->querier = orphan;
524 mdns_retain(q->querier);
525 mdns_set_remove(set, (uintptr_t)q->dnsservice, q->querier);
526 mdns_querier_set_time_limit_ms(q->querier, 0);
527 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
528 "[Q%u->Q%u] Adopted orphaned querier", mDNSVal16(q->TargetQID), mdns_querier_get_user_id(q->querier));
529 }
530 }
531 if (!q->querier)
532 {
533 querier = mdns_dns_service_create_querier(q->dnsservice, NULL);
534 require_quiet(querier, exit);
535
536 const OSStatus err = mdns_querier_set_query(querier, q->qname.c, q->qtype, q->qclass);
537 require_noerr_quiet(err, exit);
538
539 q->querier = querier;
540 mdns_retain(q->querier);
541
542 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
543 if (q->DNSSECStatus.enable_dnssec)
544 {
545 mdns_querier_set_dnssec_ok(querier, true);
546 mdns_querier_set_checking_disabled(querier, true);
547 }
548 #endif
549
550 if (q->pid != 0)
551 {
552 mdns_querier_set_delegator_pid(q->querier, q->pid);
553 }
554 else
555 {
556 mdns_querier_set_delegator_uuid(q->querier, q->uuid);
557 }
558 mdns_querier_set_queue(querier, dispatch_get_main_queue());
559 mdns_retain(querier);
560 const mdns_dns_service_t dnsservice = q->dnsservice;
561 mdns_retain(dnsservice);
562 mdns_querier_set_result_handler(querier,
563 ^{
564 _Querier_HandleQuerierResponse(querier, dnsservice);
565 mdns_release(querier);
566 mdns_release(dnsservice);
567 });
568 mdns_querier_set_log_label(querier, "Q%u", mDNSVal16(q->TargetQID));
569 mdns_querier_set_user_id(querier, mDNSVal16(q->TargetQID));
570 mdns_querier_activate(querier);
571 }
572 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
573 if (mdns_querier_get_resolver_type(q->querier) == mdns_resolver_type_normal)
574 {
575 if (q->metrics.answered)
576 {
577 uDNSMetricsClear(&q->metrics);
578 }
579 if (q->metrics.firstQueryTime == 0)
580 {
581 q->metrics.firstQueryTime = NonZeroTime(m->timenow);
582 }
583 }
584 else
585 {
586 q->metrics.firstQueryTime = 0;
587 }
588 #endif
589
590 exit:
591 q->ThisQInterval = q->querier ? MaxQuestionInterval : mDNSPlatformOneSecond;
592 q->LastQTime = m->timenow;
593 SetNextQueryTime(m, q);
594 mdns_release_null_safe(querier);
595 }
596
597 mDNSexport void Querier_ProcessDNSServiceChanges(void)
598 {
599 mDNS *const m = &mDNSStorage;
600 DNSQuestion *q;
601 DNSQuestion *restartList = NULL;
602 DNSQuestion **ptr = &restartList;
603 mDNSu32 slot;
604 CacheGroup *cg;
605 CacheRecord *cr;
606 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
607 DNSPushNotificationServer **psp;
608 #endif
609
610 m->RestartQuestion = m->Questions;
611 while ((q = m->RestartQuestion) != mDNSNULL)
612 {
613 if (mDNSOpaque16IsZero(q->TargetQID))
614 {
615 m->RestartQuestion = q->next;
616 continue;
617 }
618 mdns_dns_service_t newService = _Querier_GetDNSService(q);
619 mDNSBool forcePathEval = mDNSfalse;
620 if (q->dnsservice != newService)
621 {
622 // If the DNS service would change, but there is no new DNS service or it's unscoped and lacks privacy,
623 // force a path evaluation when the DNSQuestion restarts to determine if there's a DNS service that offers
624 // privacy that should be used. This DNSQuestion might have been unscoped so that it can use a VPN DNS
625 // service, but that service may be defunct now.
626 if (!newService || _Querier_DNSServiceIsUnscopedAndLacksPrivacy(newService))
627 {
628 forcePathEval = mDNStrue;
629 }
630 }
631 else
632 {
633 // If the DNS service wouldn't change and the DNS service is UUID-scoped, perform a path evaluation now to
634 // see if a DNS service change occurs. This might happen if a DNSQuestion was UUID-scoped to a DoH or DoT
635 // service, but there's a new VPN DNS service that handles the DNSQuestion's QNAME.
636 if (q->dnsservice && (mdns_dns_service_get_scope(q->dnsservice) == mdns_dns_service_scope_uuid))
637 {
638 mDNSPlatformGetDNSRoutePolicy(q);
639 newService = _Querier_GetDNSService(q);
640 }
641 }
642 mDNSBool restart = mDNSfalse;
643 if (q->dnsservice != newService)
644 {
645 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
646 // If this question had a DNS Push server associated with it, substitute the new server for the
647 // old one. If there is no new server, then we'll clean up the push server later.
648 if (!q->DuplicateOf && q->dnsPushServer)
649 {
650 if (q->dnsPushServer->dnsservice == q->dnsservice)
651 {
652 mdns_replace(&q->dnsPushServer->dnsservice, newService);
653 }
654 // If it is null, do the accounting and drop the push server.
655 if (!q->dnsPushServer->dnsservice)
656 {
657 DNSPushReconcileConnection(m, q);
658 }
659 }
660 #endif
661 restart = mDNStrue;
662 }
663 else
664 {
665 mDNSBool newSuppressed = ShouldSuppressUnicastQuery(q, newService);
666 if (!q->Suppressed != !newSuppressed) restart = mDNStrue;
667 }
668 if (restart)
669 {
670 if (!q->Suppressed)
671 {
672 CacheRecordRmvEventsForQuestion(m, q);
673 if (m->RestartQuestion == q) LocalRecordRmvEventsForQuestion(m, q);
674 }
675 if (m->RestartQuestion == q)
676 {
677 mDNS_StopQuery_internal(m, q);
678 q->ForcePathEval = forcePathEval;
679 q->next = mDNSNULL;
680 *ptr = q;
681 ptr = &q->next;
682 }
683 }
684 if (m->RestartQuestion == q) m->RestartQuestion = q->next;
685 }
686 while ((q = restartList) != mDNSNULL)
687 {
688 restartList = q->next;
689 q->next = mDNSNULL;
690 mDNS_StartQuery_internal(m, q);
691 }
692 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
693 // The above code may have found some DNS Push servers that are no longer valid. Now that we
694 // are done running through the code, we need to drop our connections to those servers.
695 // When we get here, any such servers should have zero questions associated with them.
696 for (psp = &m->DNSPushServers; *psp != mDNSNULL; )
697 {
698 DNSPushNotificationServer *server = *psp;
699
700 // It's possible that a push server whose DNS server has been deleted could be still connected but
701 // not referenced by any questions. In this case, we just delete the push server rather than trying
702 // to figure out with which DNS server (if any) to associate it.
703 if (server->dnsservice && mdns_dns_service_is_defunct(server->dnsservice))
704 {
705 mdns_forget(&server->dnsservice);
706 }
707 if (!server->dnsservice)
708 {
709 // This would be a programming error, so should never happen.
710 if (server->numberOfQuestions != 0)
711 {
712 LogInfo("uDNS_SetupDNSConfig: deleting push server %##s that has questions.", &server->serverName);
713 }
714 DNSPushServerDrop(server);
715 *psp = server->next;
716 mDNSPlatformMemFree(server);
717 }
718 else
719 {
720 psp = &(*psp)->next;
721 }
722 }
723 #endif
724 FORALL_CACHERECORDS(slot, cg, cr)
725 {
726 if (cr->resrec.InterfaceID) continue;
727 if (!cr->resrec.dnsservice || mdns_dns_service_is_defunct(cr->resrec.dnsservice))
728 {
729 mdns_forget(&cr->resrec.dnsservice);
730 mDNS_PurgeCacheResourceRecord(m, cr);
731 }
732 }
733 }
734
735 mDNSexport DNSQuestion *Querier_GetDNSQuestion(const mdns_querier_t querier)
736 {
737 DNSQuestion *q;
738 for (q = mDNSStorage.Questions; q; q = q->next)
739 {
740 if (q->querier == querier)
741 {
742 return q;
743 }
744 }
745 return mDNSNULL;
746 }
747
748 mDNSexport mDNSBool Querier_ResourceRecordIsAnswer(const ResourceRecord * const rr, const mdns_querier_t querier)
749 {
750 const mDNSu16 qtype = mdns_querier_get_qtype(querier);
751 const mDNSu8 *const qname = mdns_querier_get_qname(querier);
752 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
753 const mDNSBool enableDNSSEC = mdns_querier_get_dnssec_ok(querier);
754 #endif
755
756
757 if ((RRTypeAnswersQuestionType(rr, qtype)
758 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
759 || (enableDNSSEC && record_type_answers_dnssec_question(rr, qtype))
760 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
761 )
762 && (rr->rrclass == mdns_querier_get_qclass(querier)) &&
763 qname && SameDomainName(rr->name, (const domainname *)qname))
764 {
765 return mDNStrue;
766 }
767 else
768 {
769 return mDNSfalse;
770 }
771 }
772
773 mDNSexport mDNSBool Querier_SameNameCacheRecordIsAnswer(const CacheRecord *const cr, const mdns_querier_t querier)
774 {
775 const ResourceRecord *const rr = &cr->resrec;
776 const mDNSu16 qtype = mdns_querier_get_qtype(querier);
777 if (RRTypeAnswersQuestionType(rr, qtype) && (rr->rrclass == mdns_querier_get_qclass(querier)))
778 {
779 return mDNStrue;
780 }
781 else
782 {
783 return mDNSfalse;
784 }
785 }
786
787 #define kOrphanedQuerierTimeLimitSecs 5
788 #define kOrphanedQuerierSubsetCountLimit 10
789
790 mDNSexport void Querier_HandleStoppedDNSQuestion(DNSQuestion *q)
791 {
792 if (q->querier && !mdns_querier_has_concluded(q->querier) &&
793 q->dnsservice && !mdns_dns_service_is_defunct(q->dnsservice))
794 {
795 const mdns_set_t set = _Querier_GetOrphanedQuerierSet();
796 const uintptr_t subsetID = (uintptr_t)q->dnsservice;
797 if (set && (mdns_set_get_count(set, subsetID) < kOrphanedQuerierSubsetCountLimit))
798 {
799 const OSStatus err = mdns_set_add(set, subsetID, q->querier);
800 if (!err)
801 {
802 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
803 "[Q%u] Keeping orphaned querier for up to " StringifyExpansion(kOrphanedQuerierTimeLimitSecs) " seconds",
804 mdns_querier_get_user_id(q->querier));
805 mdns_querier_set_time_limit_ms(q->querier, kOrphanedQuerierTimeLimitSecs * 1000);
806 mdns_forget(&q->querier);
807 }
808 }
809 }
810 mdns_querier_forget(&q->querier);
811 mdns_forget(&q->dnsservice);
812 }
813
814 mDNSexport void Querier_PrepareQuestionForCNAMERestart(DNSQuestion *const q)
815 {
816 q->lastDNSServiceID = q->dnsservice ? mdns_dns_service_get_id(q->dnsservice) : MDNS_DNS_SERVICE_MAX_ID;
817 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
818 _Querier_UpdateQuestionMetrics(q);
819 #endif
820 }
821
822 mDNSexport void Querier_PrepareQuestionForUnwindRestart(DNSQuestion *const q)
823 {
824 q->lastDNSServiceID = 0;
825 q->ForcePathEval = mDNStrue;
826 }
827
828 mDNSexport void Querier_HandleSleep(void)
829 {
830 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
831 if (manager)
832 {
833 mdns_dns_service_manager_handle_sleep(manager);
834 }
835 }
836
837 mDNSexport void Querier_HandleWake(void)
838 {
839 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
840 if (manager)
841 {
842 mdns_dns_service_manager_handle_wake(manager);
843 }
844 }
845 #endif // MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)