2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
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
8 * https://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "QuerierSupport.h"
19 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
20 #include "DebugServices.h"
21 #include "dns_sd_internal.h"
22 #include "mDNSMacOSX.h"
26 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
30 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
31 #include "dnssec_v2.h"
35 #include <mach/mach_time.h>
36 #include "mdns_helpers.h"
38 int PQWorkaroundThreshold
= 0;
40 extern mDNS mDNSStorage
;
42 mDNSlocal
void _Querier_LogDNSServices(const mdns_dns_service_manager_t manager
)
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
)
51 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "DNS service (%u/%u) -- %@", count
, total
, service
);
56 mDNSexport mdns_dns_service_manager_t
Querier_GetDNSServiceManager(void)
58 mDNS
*const m
= &mDNSStorage
;
59 static mdns_dns_service_manager_t sDNSServiceManager
= NULL
;
60 if (sDNSServiceManager
)
62 return sDNSServiceManager
;
64 const mdns_dns_service_manager_t manager
= mdns_dns_service_manager_create(dispatch_get_main_queue(), NULL
);
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
)
77 case mdns_event_error
:
78 mdns_dns_service_manager_invalidate(manager
);
79 if (sDNSServiceManager
== manager
)
81 mdns_forget(&sDNSServiceManager
);
85 case mdns_event_update
:
86 mdns_dns_service_manager_apply_pending_updates(manager
);
88 Querier_ProcessDNSServiceChanges();
89 _Querier_LogDNSServices(manager
);
93 case mdns_event_invalidated
:
94 mdns_release(manager
);
100 KQueueUnlock("DNS Service Manager event handler");
102 sDNSServiceManager
= manager
;
103 mdns_retain(sDNSServiceManager
);
104 mdns_dns_service_manager_activate(sDNSServiceManager
);
105 return sDNSServiceManager
;
108 mDNSlocal mdns_dns_service_t
_Querier_GetDNSService(const DNSQuestion
*q
)
110 mdns_dns_service_t service
;
111 const mdns_dns_service_manager_t manager
= Querier_GetDNSServiceManager();
116 if (!uuid_is_null(q
->ResolverUUID
))
118 service
= mdns_dns_service_manager_get_uuid_scoped_service(manager
, q
->ResolverUUID
);
120 else if (q
->InterfaceID
)
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
);
125 else if (q
->ServiceID
>= 0)
127 service
= mdns_dns_service_manager_get_service_scoped_service(manager
, q
->qname
.c
, (uint32_t)q
->ServiceID
);
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
))
135 service
= mdns_dns_service_manager_get_uuid_scoped_service(manager
, discoveredResolverUUID
);
139 service
= mdns_dns_service_manager_get_unscoped_service(manager
, q
->qname
.c
);
142 if (service
&& !mdns_dns_service_interface_is_vpn(service
))
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
))
148 if (lacksRequiredEncryption
)
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
));
156 // Check for a fallback service
157 if (q
->CustomID
!= 0)
159 service
= mdns_dns_service_manager_get_custom_service(manager
, q
->CustomID
);
166 mDNSlocal pid_t
_Querier_GetMyPID(void)
168 static dispatch_once_t sOnce
= 0;
169 static pid_t sPID
= 0;
170 dispatch_once(&sOnce
,
177 mDNSlocal
const mDNSu8
*_Querier_GetMyUUID(void)
179 static dispatch_once_t sOnce
= 0;
180 static mDNSu8 sUUID
[16];
181 dispatch_once(&sOnce
,
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
))
188 uuid_copy(sUUID
, info
.p_uuid
);
194 mDNSlocal mDNSBool
_Querier_QuestionBelongsToSelf(const DNSQuestion
*q
)
198 return ((q
->pid
== _Querier_GetMyPID()) ? mDNStrue
: mDNSfalse
);
202 return ((uuid_compare(q
->uuid
, _Querier_GetMyUUID()) == 0) ? mDNStrue
: mDNSfalse
);
206 mDNSlocal mDNSBool
_Querier_DNSServiceIsUnscopedAndLacksPrivacy(const mdns_dns_service_t service
)
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
))
219 #define kQuerierLogFullDNSServicePeriodSecs 30
221 mDNSlocal mDNSBool
_Querier_ShouldLogFullDNSService(const mdns_dns_service_t service
)
223 uint64_t *lastFullLogTicks
= (uint64_t *)mdns_dns_service_get_context(service
);
224 if (lastFullLogTicks
)
226 const uint64_t nowTicks
= mach_continuous_time();
227 const uint64_t diffTicks
= nowTicks
- *lastFullLogTicks
;
228 if ((diffTicks
/ mdns_mach_ticks_per_second()) < kQuerierLogFullDNSServicePeriodSecs
)
232 *lastFullLogTicks
= nowTicks
;
236 lastFullLogTicks
= (uint64_t *)malloc(sizeof(*lastFullLogTicks
));
237 if (lastFullLogTicks
)
239 *lastFullLogTicks
= mach_continuous_time();
240 mdns_dns_service_set_context(service
, lastFullLogTicks
);
241 mdns_dns_service_set_context_finalizer(service
, free
);
247 mDNSexport
void Querier_SetDNSServiceForQuestion(DNSQuestion
*q
)
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
))
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
));
260 mdns_forget(&q
->dnsservice
);
261 mDNSBool retryPathEval
= mDNSfalse
;
262 mdns_dns_service_t service
= _Querier_GetDNSService(q
);
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
))
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
;
279 else if (!uuid_is_null(q
->ResolverUUID
))
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
;
290 mDNSPlatformGetDNSRoutePolicy(q
);
291 service
= _Querier_GetDNSService(q
);
293 q
->dnsservice
= service
;
294 mdns_retain_null_safe(q
->dnsservice
);
295 if (!q
->dnsservice
|| _Querier_ShouldLogFullDNSService(q
->dnsservice
))
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
);
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
));
310 mDNSexport
void Querier_RegisterPathResolver(const uuid_t resolverUUID
)
312 const mdns_dns_service_manager_t manager
= Querier_GetDNSServiceManager();
315 mdns_dns_service_manager_register_path_resolver(manager
, resolverUUID
);
319 mDNSexport mdns_dns_service_id_t
Querier_RegisterCustomDNSService(const xpc_object_t resolverConfigDict
)
321 mdns_dns_service_id_t ident
= 0;
322 const mdns_dns_service_manager_t manager
= Querier_GetDNSServiceManager();
325 ident
= mdns_dns_service_manager_register_custom_service(manager
, resolverConfigDict
);
330 mDNSexport mdns_dns_service_id_t
Querier_RegisterCustomDNSServiceWithPListData(const uint8_t *dataPtr
, size_t dataLen
)
332 mdns_dns_service_id_t ident
= 0;
333 const mdns_dns_service_manager_t manager
= Querier_GetDNSServiceManager();
336 xpc_object_t resolverConfigDict
= mdns_xpc_create_dictionary_from_plist_data(dataPtr
, dataLen
, NULL
);
337 if (resolverConfigDict
)
339 ident
= mdns_dns_service_manager_register_custom_service(manager
, resolverConfigDict
);
340 xpc_release(resolverConfigDict
);
346 mDNSexport
void Querier_DeregisterCustomDNSService(const mdns_dns_service_id_t ident
)
348 const mdns_dns_service_manager_t manager
= Querier_GetDNSServiceManager();
351 mdns_dns_service_manager_deregister_custom_service(manager
, ident
);
355 mDNSexport
void Querier_RegisterDoHURI(const char *doh_uri
, const char *domain
)
357 const mdns_dns_service_manager_t manager
= Querier_GetDNSServiceManager();
360 mdns_dns_service_manager_register_doh_uri(manager
, doh_uri
, domain
);
364 mDNSexport
void Querier_ApplyDNSConfig(const dns_config_t
*config
)
366 const mdns_dns_service_manager_t manager
= Querier_GetDNSServiceManager();
369 mdns_dns_service_manager_apply_dns_config(manager
, config
);
370 _Querier_LogDNSServices(manager
);
374 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
375 mDNSlocal
void _Querier_UpdateQuestionMetrics(DNSQuestion
*const q
)
377 if (q
->querier
&& (mdns_querier_get_resolver_type(q
->querier
) == mdns_resolver_type_normal
))
379 q
->metrics
.querySendCount
+= mdns_querier_get_send_count(q
->querier
);
380 if (q
->metrics
.dnsOverTCPState
== DNSOverTCP_None
)
382 switch (mdns_querier_get_over_tcp_reason(q
->querier
))
384 case mdns_query_over_tcp_reason_truncation
:
385 q
->metrics
.dnsOverTCPState
= DNSOverTCP_Truncated
;
388 case mdns_query_over_tcp_reason_got_suspicious_reply
:
389 q
->metrics
.dnsOverTCPState
= DNSOverTCP_Suspicious
;
392 case mdns_query_over_tcp_reason_in_suspicious_mode
:
393 q
->metrics
.dnsOverTCPState
= DNSOverTCP_SuspiciousDefense
;
403 mDNSlocal
void _Querier_UpdateDNSMessageSizeMetrics(const mdns_querier_t querier
)
405 if (mdns_querier_get_resolver_type(querier
) == mdns_resolver_type_normal
)
407 if (mdns_querier_get_send_count(querier
) > 0)
409 const mDNSu32 len
= mdns_querier_get_query_length(querier
);
412 MetricsUpdateDNSQuerySize(len
);
415 if ((mdns_querier_get_result_type(querier
) == mdns_querier_result_type_response
) &&
416 !mdns_querier_response_is_fabricated(querier
))
418 const mDNSu32 len
= mdns_querier_get_response_length(querier
);
421 MetricsUpdateDNSResponseSize(len
);
428 mDNSlocal mdns_set_t
_Querier_GetOrphanedQuerierSet(void)
430 static mdns_set_t sOrphanedQuerierSet
= NULL
;
431 if (!sOrphanedQuerierSet
)
433 sOrphanedQuerierSet
= mdns_set_create();
435 return sOrphanedQuerierSet
;
438 mDNSlocal
void _Querier_HandleQuerierResponse(const mdns_querier_t querier
, const mdns_dns_service_t dnsservice
)
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
);
446 const mdns_querier_result_type_t resultType
= mdns_querier_get_result_type(querier
);
447 if (resultType
== mdns_querier_result_type_response
)
449 mDNS
*const m
= &mDNSStorage
;
450 if (!mdns_dns_service_is_defunct(dnsservice
))
452 size_t copyLen
= mdns_querier_get_response_length(querier
);
453 if (copyLen
> sizeof(m
->imsg
.m
))
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
);
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
);
465 const mdns_set_t set
= _Querier_GetOrphanedQuerierSet();
468 mdns_set_remove(set
, (uintptr_t)dnsservice
, querier
);
470 DNSQuestion
*const q
= Querier_GetDNSQuestion(querier
);
473 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
474 _Querier_UpdateQuestionMetrics(q
);
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
)
481 Querier_HandleUnicastQuestion(q
);
483 else if (resultType
== mdns_querier_result_type_error
)
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
488 mDNS
*const m
= &mDNSStorage
;
489 q
->ThisQInterval
= 5 * mDNSPlatformOneSecond
;
490 q
->LastQTime
= m
->timenow
;
491 SetNextQueryTime(m
, q
);
494 KQueueUnlock("_Querier_HandleQuerierResponse");
497 mDNSexport
void Querier_HandleUnicastQuestion(DNSQuestion
*q
)
499 mDNS
*const m
= &mDNSStorage
;
500 mdns_querier_t querier
= NULL
;
501 if (!q
->dnsservice
|| q
->querier
) goto exit
;
503 const mdns_set_t set
= _Querier_GetOrphanedQuerierSet();
506 __block mdns_querier_t orphan
= NULL
;
507 mdns_set_iterate(set
, (uintptr_t)q
->dnsservice
,
508 ^ bool (mdns_object_t _Nonnull object
)
510 const mdns_querier_t candidate
= (mdns_querier_t
)object
;
511 if (mdns_querier_match(candidate
, q
->qname
.c
, q
->qtype
, q
->qclass
))
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
));
533 querier
= mdns_dns_service_create_querier(q
->dnsservice
, NULL
);
534 require_quiet(querier
, exit
);
536 const OSStatus err
= mdns_querier_set_query(querier
, q
->qname
.c
, q
->qtype
, q
->qclass
);
537 require_noerr_quiet(err
, exit
);
539 q
->querier
= querier
;
540 mdns_retain(q
->querier
);
542 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
543 if (q
->DNSSECStatus
.enable_dnssec
)
545 mdns_querier_set_dnssec_ok(querier
, true);
546 mdns_querier_set_checking_disabled(querier
, true);
552 mdns_querier_set_delegator_pid(q
->querier
, q
->pid
);
556 mdns_querier_set_delegator_uuid(q
->querier
, q
->uuid
);
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
,
564 _Querier_HandleQuerierResponse(querier
, dnsservice
);
565 mdns_release(querier
);
566 mdns_release(dnsservice
);
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
);
572 #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
573 if (mdns_querier_get_resolver_type(q
->querier
) == mdns_resolver_type_normal
)
575 if (q
->metrics
.answered
)
577 uDNSMetricsClear(&q
->metrics
);
579 if (q
->metrics
.firstQueryTime
== 0)
581 q
->metrics
.firstQueryTime
= NonZeroTime(m
->timenow
);
586 q
->metrics
.firstQueryTime
= 0;
591 q
->ThisQInterval
= q
->querier
? MaxQuestionInterval
: mDNSPlatformOneSecond
;
592 q
->LastQTime
= m
->timenow
;
593 SetNextQueryTime(m
, q
);
594 mdns_release_null_safe(querier
);
597 mDNSexport
void Querier_ProcessDNSServiceChanges(void)
599 mDNS
*const m
= &mDNSStorage
;
601 DNSQuestion
*restartList
= NULL
;
602 DNSQuestion
**ptr
= &restartList
;
606 #if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
607 DNSPushNotificationServer
**psp
;
610 m
->RestartQuestion
= m
->Questions
;
611 while ((q
= m
->RestartQuestion
) != mDNSNULL
)
613 if (mDNSOpaque16IsZero(q
->TargetQID
))
615 m
->RestartQuestion
= q
->next
;
618 mdns_dns_service_t newService
= _Querier_GetDNSService(q
);
619 mDNSBool forcePathEval
= mDNSfalse
;
620 if (q
->dnsservice
!= newService
)
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
))
628 forcePathEval
= mDNStrue
;
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
))
638 mDNSPlatformGetDNSRoutePolicy(q
);
639 newService
= _Querier_GetDNSService(q
);
642 mDNSBool restart
= mDNSfalse
;
643 if (q
->dnsservice
!= newService
)
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
)
650 if (q
->dnsPushServer
->dnsservice
== q
->dnsservice
)
652 mdns_replace(&q
->dnsPushServer
->dnsservice
, newService
);
654 // If it is null, do the accounting and drop the push server.
655 if (!q
->dnsPushServer
->dnsservice
)
657 DNSPushReconcileConnection(m
, q
);
665 mDNSBool newSuppressed
= ShouldSuppressUnicastQuery(q
, newService
);
666 if (!q
->Suppressed
!= !newSuppressed
) restart
= mDNStrue
;
672 CacheRecordRmvEventsForQuestion(m
, q
);
673 if (m
->RestartQuestion
== q
) LocalRecordRmvEventsForQuestion(m
, q
);
675 if (m
->RestartQuestion
== q
)
677 mDNS_StopQuery_internal(m
, q
);
678 q
->ForcePathEval
= forcePathEval
;
684 if (m
->RestartQuestion
== q
) m
->RestartQuestion
= q
->next
;
686 while ((q
= restartList
) != mDNSNULL
)
688 restartList
= q
->next
;
690 mDNS_StartQuery_internal(m
, q
);
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
; )
698 DNSPushNotificationServer
*server
= *psp
;
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
))
705 mdns_forget(&server
->dnsservice
);
707 if (!server
->dnsservice
)
709 // This would be a programming error, so should never happen.
710 if (server
->numberOfQuestions
!= 0)
712 LogInfo("uDNS_SetupDNSConfig: deleting push server %##s that has questions.", &server
->serverName
);
714 DNSPushServerDrop(server
);
716 mDNSPlatformMemFree(server
);
724 FORALL_CACHERECORDS(slot
, cg
, cr
)
726 if (cr
->resrec
.InterfaceID
) continue;
727 if (!cr
->resrec
.dnsservice
|| mdns_dns_service_is_defunct(cr
->resrec
.dnsservice
))
729 mdns_forget(&cr
->resrec
.dnsservice
);
730 mDNS_PurgeCacheResourceRecord(m
, cr
);
735 mDNSexport DNSQuestion
*Querier_GetDNSQuestion(const mdns_querier_t querier
)
738 for (q
= mDNSStorage
.Questions
; q
; q
= q
->next
)
740 if (q
->querier
== querier
)
748 mDNSexport mDNSBool
Querier_ResourceRecordIsAnswer(const ResourceRecord
* const rr
, const mdns_querier_t querier
)
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
);
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)
762 && (rr
->rrclass
== mdns_querier_get_qclass(querier
)) &&
763 qname
&& SameDomainName(rr
->name
, (const domainname
*)qname
))
773 mDNSexport mDNSBool
Querier_SameNameCacheRecordIsAnswer(const CacheRecord
*const cr
, const mdns_querier_t querier
)
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
)))
787 #define kOrphanedQuerierTimeLimitSecs 5
788 #define kOrphanedQuerierSubsetCountLimit 10
790 mDNSexport
void Querier_HandleStoppedDNSQuestion(DNSQuestion
*q
)
792 if (q
->querier
&& !mdns_querier_has_concluded(q
->querier
) &&
793 q
->dnsservice
&& !mdns_dns_service_is_defunct(q
->dnsservice
))
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
))
799 const OSStatus err
= mdns_set_add(set
, subsetID
, q
->querier
);
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
);
810 mdns_querier_forget(&q
->querier
);
811 mdns_forget(&q
->dnsservice
);
814 mDNSexport
void Querier_PrepareQuestionForCNAMERestart(DNSQuestion
*const q
)
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
);
822 mDNSexport
void Querier_PrepareQuestionForUnwindRestart(DNSQuestion
*const q
)
824 q
->lastDNSServiceID
= 0;
825 q
->ForcePathEval
= mDNStrue
;
828 mDNSexport
void Querier_HandleSleep(void)
830 const mdns_dns_service_manager_t manager
= Querier_GetDNSServiceManager();
833 mdns_dns_service_manager_handle_sleep(manager
);
837 mDNSexport
void Querier_HandleWake(void)
839 const mdns_dns_service_manager_t manager
= Querier_GetDNSServiceManager();
842 mdns_dns_service_manager_handle_wake(manager
);
845 #endif // MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)