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