1 /*
2 * Copyright (c) 2019-2021 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
_Querier_LogDNSServices(const mdns_dns_service_manager_t manager)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
Querier_GetDNSServiceManager(void)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
_Querier_GetDNSService(const DNSQuestion * q)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
_Querier_GetMyPID(void)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
_Querier_GetMyUUID(void)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
_Querier_QuestionBelongsToSelf(const DNSQuestion * q)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
_Querier_DNSServiceIsUnscopedAndLacksPrivacy(const mdns_dns_service_t service)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
_Querier_ShouldLogFullDNSService(const mdns_dns_service_t service)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
Querier_SetDNSServiceForQuestion(DNSQuestion * q)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
Querier_RegisterPathResolver(const uuid_t resolverUUID)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
Querier_RegisterCustomDNSService(const xpc_object_t resolverConfigDict)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
Querier_RegisterCustomDNSServiceWithPListData(const uint8_t * dataPtr,size_t dataLen)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
Querier_DeregisterCustomDNSService(const mdns_dns_service_id_t ident)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
Querier_RegisterDoHURI(const char * doh_uri,const char * domain)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
Querier_ApplyDNSConfig(const dns_config_t * config)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)
_Querier_UpdateQuestionMetrics(DNSQuestion * const q)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
_Querier_UpdateDNSMessageSizeMetrics(const mdns_querier_t querier)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
_Querier_GetOrphanedQuerierSet(void)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
_Querier_HandleQuerierResponse(const mdns_querier_t querier,const mdns_dns_service_t dnsservice)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
Querier_HandleUnicastQuestion(DNSQuestion * q)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
_Querier_GetQuestionCount(void)597 mDNSlocal mDNSu32 _Querier_GetQuestionCount(void)
598 {
599 mDNSu32 count = 0;
600 for (const DNSQuestion *q = mDNSStorage.Questions; q; q = q->next)
601 {
602 count++;
603 }
604 return count;
605 }
606
Querier_ProcessDNSServiceChanges(void)607 mDNSexport void Querier_ProcessDNSServiceChanges(void)
608 {
609 mDNS *const m = &mDNSStorage;
610 mDNSu32 slot;
611 CacheGroup *cg;
612 CacheRecord *cr;
613 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
614 DNSPushNotificationServer **psp;
615 #endif
616
617 const mDNSu32 count = _Querier_GetQuestionCount();
618 m->RestartQuestion = m->Questions;
619 for (mDNSu32 i = 0; (i < count) && m->RestartQuestion; i++)
620 {
621 DNSQuestion *const q = m->RestartQuestion;
622 if (mDNSOpaque16IsZero(q->TargetQID))
623 {
624 m->RestartQuestion = q->next;
625 continue;
626 }
627 mdns_dns_service_t newService = _Querier_GetDNSService(q);
628 mDNSBool forcePathEval = mDNSfalse;
629 if (q->dnsservice != newService)
630 {
631 // If the DNS service would change, but there is no new DNS service or it's unscoped and lacks privacy,
632 // force a path evaluation when the DNSQuestion restarts to determine if there's a DNS service that offers
633 // privacy that should be used. This DNSQuestion might have been unscoped so that it can use a VPN DNS
634 // service, but that service may be defunct now.
635 if (!newService || _Querier_DNSServiceIsUnscopedAndLacksPrivacy(newService))
636 {
637 forcePathEval = mDNStrue;
638 }
639 }
640 else
641 {
642 // If the DNS service wouldn't change and the DNS service is UUID-scoped, perform a path evaluation now to
643 // see if a DNS service change occurs. This might happen if a DNSQuestion was UUID-scoped to a DoH or DoT
644 // service, but there's a new VPN DNS service that handles the DNSQuestion's QNAME.
645 if (q->dnsservice && (mdns_dns_service_get_scope(q->dnsservice) == mdns_dns_service_scope_uuid))
646 {
647 mDNSPlatformGetDNSRoutePolicy(q);
648 newService = _Querier_GetDNSService(q);
649 }
650 }
651 mDNSBool restart = mDNSfalse;
652 if (q->dnsservice != newService)
653 {
654 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
655 // If this question had a DNS Push server associated with it, substitute the new server for the
656 // old one. If there is no new server, then we'll clean up the push server later.
657 if (!q->DuplicateOf && q->dnsPushServer)
658 {
659 if (q->dnsPushServer->dnsservice == q->dnsservice)
660 {
661 mdns_replace(&q->dnsPushServer->dnsservice, newService);
662 }
663 // If it is null, do the accounting and drop the push server.
664 if (!q->dnsPushServer->dnsservice)
665 {
666 DNSPushReconcileConnection(m, q);
667 }
668 }
669 #endif
670 restart = mDNStrue;
671 }
672 else
673 {
674 mDNSBool newSuppressed = ShouldSuppressUnicastQuery(q, newService);
675 if (!q->Suppressed != !newSuppressed) restart = mDNStrue;
676 }
677 if (restart)
678 {
679 if (!q->Suppressed)
680 {
681 CacheRecordRmvEventsForQuestion(m, q);
682 if (m->RestartQuestion == q) LocalRecordRmvEventsForQuestion(m, q);
683 }
684 if (m->RestartQuestion == q)
685 {
686 mDNS_StopQuery_internal(m, q);
687 q->ForcePathEval = forcePathEval;
688 q->next = mDNSNULL;
689 mDNS_StartQuery_internal(m, q);
690 }
691 }
692 if (m->RestartQuestion == q) m->RestartQuestion = q->next;
693 }
694 m->RestartQuestion = mDNSNULL;
695 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
696 // The above code may have found some DNS Push servers that are no longer valid. Now that we
697 // are done running through the code, we need to drop our connections to those servers.
698 // When we get here, any such servers should have zero questions associated with them.
699 for (psp = &m->DNSPushServers; *psp != mDNSNULL; )
700 {
701 DNSPushNotificationServer *server = *psp;
702
703 // It's possible that a push server whose DNS server has been deleted could be still connected but
704 // not referenced by any questions. In this case, we just delete the push server rather than trying
705 // to figure out with which DNS server (if any) to associate it.
706 if (server->dnsservice && mdns_dns_service_is_defunct(server->dnsservice))
707 {
708 mdns_forget(&server->dnsservice);
709 }
710 if (!server->dnsservice)
711 {
712 // This would be a programming error, so should never happen.
713 if (server->numberOfQuestions != 0)
714 {
715 LogInfo("uDNS_SetupDNSConfig: deleting push server %##s that has questions.", &server->serverName);
716 }
717 DNSPushServerDrop(server);
718 *psp = server->next;
719 mDNSPlatformMemFree(server);
720 }
721 else
722 {
723 psp = &(*psp)->next;
724 }
725 }
726 #endif
727 FORALL_CACHERECORDS(slot, cg, cr)
728 {
729 if (cr->resrec.InterfaceID) continue;
730 if (!cr->resrec.dnsservice || mdns_dns_service_is_defunct(cr->resrec.dnsservice))
731 {
732 mdns_forget(&cr->resrec.dnsservice);
733 mDNS_PurgeCacheResourceRecord(m, cr);
734 }
735 }
736 }
737
Querier_GetDNSQuestion(const mdns_querier_t querier)738 mDNSexport DNSQuestion *Querier_GetDNSQuestion(const mdns_querier_t querier)
739 {
740 DNSQuestion *q;
741 for (q = mDNSStorage.Questions; q; q = q->next)
742 {
743 if (q->querier == querier)
744 {
745 return q;
746 }
747 }
748 return mDNSNULL;
749 }
750
Querier_ResourceRecordIsAnswer(const ResourceRecord * const rr,const mdns_querier_t querier)751 mDNSexport mDNSBool Querier_ResourceRecordIsAnswer(const ResourceRecord * const rr, const mdns_querier_t querier)
752 {
753 const mDNSu16 qtype = mdns_querier_get_qtype(querier);
754 const mDNSu8 *const qname = mdns_querier_get_qname(querier);
755 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
756 const mDNSBool enableDNSSEC = mdns_querier_get_dnssec_ok(querier);
757 #endif
758
759
760 if ((RRTypeAnswersQuestionType(rr, qtype)
761 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
762 || (enableDNSSEC && record_type_answers_dnssec_question(rr, qtype))
763 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
764 )
765 && (rr->rrclass == mdns_querier_get_qclass(querier)) &&
766 qname && SameDomainName(rr->name, (const domainname *)qname))
767 {
768 return mDNStrue;
769 }
770 else
771 {
772 return mDNSfalse;
773 }
774 }
775
Querier_SameNameCacheRecordIsAnswer(const CacheRecord * const cr,const mdns_querier_t querier)776 mDNSexport mDNSBool Querier_SameNameCacheRecordIsAnswer(const CacheRecord *const cr, const mdns_querier_t querier)
777 {
778 const ResourceRecord *const rr = &cr->resrec;
779 const mDNSu16 qtype = mdns_querier_get_qtype(querier);
780 if (RRTypeAnswersQuestionType(rr, qtype) && (rr->rrclass == mdns_querier_get_qclass(querier)))
781 {
782 return mDNStrue;
783 }
784 else
785 {
786 return mDNSfalse;
787 }
788 }
789
790 #define kOrphanedQuerierTimeLimitSecs 5
791 #define kOrphanedQuerierSubsetCountLimit 10
792
Querier_HandleStoppedDNSQuestion(DNSQuestion * q)793 mDNSexport void Querier_HandleStoppedDNSQuestion(DNSQuestion *q)
794 {
795 if (q->querier && !mdns_querier_has_concluded(q->querier) &&
796 q->dnsservice && !mdns_dns_service_is_defunct(q->dnsservice))
797 {
798 const mdns_set_t set = _Querier_GetOrphanedQuerierSet();
799 const uintptr_t subsetID = (uintptr_t)q->dnsservice;
800 if (set && (mdns_set_get_count(set, subsetID) < kOrphanedQuerierSubsetCountLimit))
801 {
802 const OSStatus err = mdns_set_add(set, subsetID, q->querier);
803 if (!err)
804 {
805 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
806 "[Q%u] Keeping orphaned querier for up to " StringifyExpansion(kOrphanedQuerierTimeLimitSecs) " seconds",
807 mdns_querier_get_user_id(q->querier));
808 mdns_querier_set_time_limit_ms(q->querier, kOrphanedQuerierTimeLimitSecs * 1000);
809 mdns_forget(&q->querier);
810 }
811 }
812 }
813 mdns_querier_forget(&q->querier);
814 mdns_forget(&q->dnsservice);
815 }
816
Querier_PrepareQuestionForCNAMERestart(DNSQuestion * const q)817 mDNSexport void Querier_PrepareQuestionForCNAMERestart(DNSQuestion *const q)
818 {
819 q->lastDNSServiceID = q->dnsservice ? mdns_dns_service_get_id(q->dnsservice) : MDNS_DNS_SERVICE_MAX_ID;
820 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
821 _Querier_UpdateQuestionMetrics(q);
822 #endif
823 }
824
Querier_PrepareQuestionForUnwindRestart(DNSQuestion * const q)825 mDNSexport void Querier_PrepareQuestionForUnwindRestart(DNSQuestion *const q)
826 {
827 q->lastDNSServiceID = 0;
828 q->ForcePathEval = mDNStrue;
829 }
830
Querier_HandleSleep(void)831 mDNSexport void Querier_HandleSleep(void)
832 {
833 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
834 if (manager)
835 {
836 mdns_dns_service_manager_handle_sleep(manager);
837 }
838 }
839
Querier_HandleWake(void)840 mDNSexport void Querier_HandleWake(void)
841 {
842 const mdns_dns_service_manager_t manager = Querier_GetDNSServiceManager();
843 if (manager)
844 {
845 mdns_dns_service_manager_handle_wake(manager);
846 }
847 }
848 #endif // MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
849