2 * Copyright (c) 2018-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 * http://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 "ClientRequests.h"
19 #include "DNSCommon.h"
22 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
23 #include "QuerierSupport.h"
26 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
30 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
31 #include "mDNSMacOSX.h"
34 #if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
35 #include <dispatch/dispatch.h>
39 #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
40 #include <WebFilterDNS/WebFilterDNS.h>
42 int WCFIsServerRunning(WCFConnection
*conn
) __attribute__((weak_import
));
43 int WCFNameResolvesToAddr(WCFConnection
*conn
, char* domainName
, struct sockaddr
* address
, uid_t userid
) __attribute__((weak_import
));
44 int WCFNameResolvesToName(WCFConnection
*conn
, char* fromName
, char* toName
, uid_t userid
) __attribute__((weak_import
));
47 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
48 #include "dnssec_v2.h"
51 #define RecordTypeIsAddress(TYPE) (((TYPE) == kDNSType_A) || ((TYPE) == kDNSType_AAAA))
53 extern mDNS mDNSStorage
;
54 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
55 extern domainname ActiveDirectoryPrimaryDomain
;
58 // Normally we append search domains only for queries with a single label that are not fully qualified. This can be
59 // overridden to apply search domains for queries (that are not fully qualified) with any number of labels e.g., moon,
60 // moon.cs, moon.cs.be, etc. - Mohan
61 mDNSBool AlwaysAppendSearchDomains
= mDNSfalse
;
63 // Control enabling optimistic DNS - Phil
64 mDNSBool EnableAllowExpired
= mDNStrue
;
70 const domainname
* qname
;
73 mDNSInterfaceID interfaceID
;
76 mDNSBool appendSearchDomains
;
78 const mDNSu8
* effectiveUUID
;
80 mDNSBool isInAppBrowserRequest
;
81 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
82 const mDNSu8
* resolverUUID
;
83 mdns_dns_service_id_t customID
;
84 mDNSBool needEncryption
;
86 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
87 const audit_token_t
* peerAuditToken
;
88 const audit_token_t
* delegatorAuditToken
;
91 } QueryRecordOpParams
;
93 mDNSlocal
void QueryRecordOpParamsInit(QueryRecordOpParams
*inParams
)
95 mDNSPlatformMemZero(inParams
, (mDNSu32
)sizeof(*inParams
));
96 inParams
->serviceID
= -1;
99 mDNSlocal mStatus
QueryRecordOpCreate(QueryRecordOp
**outOp
);
100 mDNSlocal
void QueryRecordOpFree(QueryRecordOp
*operation
);
101 mDNSlocal mStatus
QueryRecordOpStart(QueryRecordOp
*inOp
, const QueryRecordOpParams
*inParams
,
102 QueryRecordResultHandler inResultHandler
, void *inResultContext
);
103 mDNSlocal
void QueryRecordOpStop(QueryRecordOp
*op
);
104 mDNSlocal mDNSBool
QueryRecordOpIsMulticast(const QueryRecordOp
*op
);
105 mDNSlocal
void QueryRecordOpCallback(mDNS
*m
, DNSQuestion
*inQuestion
, const ResourceRecord
*inAnswer
,
106 QC_result inAddRecord
);
107 mDNSlocal
void QueryRecordOpResetHandler(DNSQuestion
*inQuestion
);
108 mDNSlocal mStatus
QueryRecordOpStartQuestion(QueryRecordOp
*inOp
, DNSQuestion
*inQuestion
);
109 mDNSlocal mStatus
QueryRecordOpStopQuestion(DNSQuestion
*inQuestion
);
110 mDNSlocal mStatus
QueryRecordOpRestartUnicastQuestion(QueryRecordOp
*inOp
, DNSQuestion
*inQuestion
,
111 const domainname
*inSearchDomain
);
112 mDNSlocal mStatus
InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex
, mDNSInterfaceID
*outInterfaceID
);
113 mDNSlocal mDNSBool
DomainNameIsSingleLabel(const domainname
*inName
);
114 mDNSlocal mDNSBool
StringEndsWithDot(const char *inString
);
115 mDNSlocal
const domainname
* NextSearchDomain(QueryRecordOp
*inOp
);
116 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
117 mDNSlocal mDNSBool
DomainNameIsInSearchList(const domainname
*domain
, mDNSBool inExcludeLocal
);
119 #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
120 mDNSlocal
void NotifyWebContentFilter(const ResourceRecord
*inAnswer
, uid_t inUID
);
123 mDNSexport
void GetAddrInfoClientRequestParamsInit(GetAddrInfoClientRequestParams
*inParams
)
125 mDNSPlatformMemZero(inParams
, (mDNSu32
)sizeof(*inParams
));
128 mDNSexport mStatus
GetAddrInfoClientRequestStart(GetAddrInfoClientRequest
*inRequest
,
129 const GetAddrInfoClientRequestParams
*inParams
, QueryRecordResultHandler inResultHandler
, void *inResultContext
)
133 mDNSBool appendSearchDomains
;
134 mDNSInterfaceID interfaceID
;
135 DNSServiceFlags flags
;
137 QueryRecordOpParams opParams
;
139 if (!MakeDomainNameFromDNSNameString(&hostname
, inParams
->hostnameStr
))
141 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
142 "[R%u] ERROR: bad hostname '" PRI_S
"'", inParams
->requestID
, inParams
->hostnameStr
);
143 err
= mStatus_BadParamErr
;
147 if (inParams
->protocols
& ~(kDNSServiceProtocol_IPv4
|kDNSServiceProtocol_IPv6
))
149 err
= mStatus_BadParamErr
;
153 flags
= inParams
->flags
;
154 if (inParams
->protocols
== 0)
156 flags
|= kDNSServiceFlagsSuppressUnusable
;
157 inRequest
->protocols
= kDNSServiceProtocol_IPv4
| kDNSServiceProtocol_IPv6
;
161 inRequest
->protocols
= inParams
->protocols
;
164 if (flags
& kDNSServiceFlagsServiceIndex
)
166 // NOTE: kDNSServiceFlagsServiceIndex flag can only be set for DNSServiceGetAddrInfo()
167 LogInfo("GetAddrInfoClientRequestStart: kDNSServiceFlagsServiceIndex is SET by the client");
169 // If kDNSServiceFlagsServiceIndex is SET, interpret the interfaceID as the serviceId and set the interfaceID to 0.
170 serviceID
= (mDNSs32
)inParams
->interfaceIndex
;
171 interfaceID
= mDNSNULL
;
176 err
= InterfaceIndexToInterfaceID(inParams
->interfaceIndex
, &interfaceID
);
179 inRequest
->interfaceID
= interfaceID
;
181 if (!StringEndsWithDot(inParams
->hostnameStr
) && (AlwaysAppendSearchDomains
|| DomainNameIsSingleLabel(&hostname
)))
183 appendSearchDomains
= mDNStrue
;
187 appendSearchDomains
= mDNSfalse
;
189 QueryRecordOpParamsInit(&opParams
);
190 opParams
.requestID
= inParams
->requestID
;
191 opParams
.qname
= &hostname
;
192 opParams
.qclass
= kDNSClass_IN
;
193 opParams
.interfaceID
= inRequest
->interfaceID
;
194 opParams
.serviceID
= serviceID
;
195 opParams
.flags
= flags
;
196 opParams
.appendSearchDomains
= appendSearchDomains
;
197 opParams
.effectivePID
= inParams
->effectivePID
;
198 opParams
.effectiveUUID
= inParams
->effectiveUUID
;
199 opParams
.peerUID
= inParams
->peerUID
;
200 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
201 opParams
.resolverUUID
= inParams
->resolverUUID
;
202 opParams
.customID
= inParams
->customID
;
203 opParams
.needEncryption
= inParams
->needEncryption
;
205 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
206 opParams
.peerAuditToken
= inParams
->peerAuditToken
;
207 opParams
.delegatorAuditToken
= inParams
->delegatorAuditToken
;
208 opParams
.isInAppBrowserRequest
= inParams
->isInAppBrowserRequest
;
210 if (inRequest
->protocols
& kDNSServiceProtocol_IPv6
)
212 err
= QueryRecordOpCreate(&inRequest
->op6
);
215 opParams
.qtype
= kDNSType_AAAA
;
216 err
= QueryRecordOpStart(inRequest
->op6
, &opParams
, inResultHandler
, inResultContext
);
219 if (inRequest
->protocols
& kDNSServiceProtocol_IPv4
)
221 err
= QueryRecordOpCreate(&inRequest
->op4
);
224 opParams
.qtype
= kDNSType_A
;
225 err
= QueryRecordOpStart(inRequest
->op4
, &opParams
, inResultHandler
, inResultContext
);
228 err
= mStatus_NoError
;
231 if (err
) GetAddrInfoClientRequestStop(inRequest
);
235 mDNSexport
void GetAddrInfoClientRequestStop(GetAddrInfoClientRequest
*inRequest
)
237 if (inRequest
->op4
) QueryRecordOpStop(inRequest
->op4
);
238 if (inRequest
->op6
) QueryRecordOpStop(inRequest
->op6
);
240 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
242 const QueryRecordOp
* const op4
= inRequest
->op4
;
243 const QueryRecordOp
* const op6
= inRequest
->op6
;
244 const DNSQuestion
* q4
= mDNSNULL
;
245 const DNSQuestion
* q6
= mDNSNULL
;
251 // If we have a v4 answer and if we timed out prematurely before, provide a trigger to the upper layer so
252 // that it can retry questions if needed. - Mohan
255 else if (op4
->q
.TimeoutQuestion
)
257 // If we are not delivering answers, we may be timing out prematurely. Note down the current state so that
258 // we know to retry when we see a valid response again. - Mohan
259 mDNSPlatformUpdateDNSStatus(&op4
->q
);
268 else if (op6
->q
.TimeoutQuestion
)
270 mDNSPlatformUpdateDNSStatus(&op6
->q
);
273 mDNSPlatformTriggerDNSRetry(q4
, q6
);
279 QueryRecordOpFree(inRequest
->op4
);
280 inRequest
->op4
= mDNSNULL
;
284 QueryRecordOpFree(inRequest
->op6
);
285 inRequest
->op6
= mDNSNULL
;
289 mDNSexport
const domainname
* GetAddrInfoClientRequestGetQName(const GetAddrInfoClientRequest
*inRequest
)
291 if (inRequest
->op4
) return &inRequest
->op4
->q
.qname
;
292 if (inRequest
->op6
) return &inRequest
->op6
->q
.qname
;
293 return (const domainname
*)"";
296 mDNSexport mDNSBool
GetAddrInfoClientRequestIsMulticast(const GetAddrInfoClientRequest
*inRequest
)
298 if ((inRequest
->op4
&& QueryRecordOpIsMulticast(inRequest
->op4
)) ||
299 (inRequest
->op6
&& QueryRecordOpIsMulticast(inRequest
->op6
)))
306 mDNSexport
void QueryRecordClientRequestParamsInit(QueryRecordClientRequestParams
*inParams
)
308 mDNSPlatformMemZero(inParams
, (mDNSu32
)sizeof(*inParams
));
311 mDNSexport mStatus
QueryRecordClientRequestStart(QueryRecordClientRequest
*inRequest
,
312 const QueryRecordClientRequestParams
*inParams
, QueryRecordResultHandler inResultHandler
, void *inResultContext
)
316 mDNSInterfaceID interfaceID
;
317 mDNSBool appendSearchDomains
;
318 QueryRecordOpParams opParams
;
319 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
320 dnssec_context_t
* dnssecContext
= mDNSNULL
;
323 err
= InterfaceIndexToInterfaceID(inParams
->interfaceIndex
, &interfaceID
);
326 if (!MakeDomainNameFromDNSNameString(&qname
, inParams
->qnameStr
))
328 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
329 "[R%u] ERROR: bad domain name '" PRI_S
"'", inParams
->requestID
, inParams
->qnameStr
);
330 err
= mStatus_BadParamErr
;
334 if (RecordTypeIsAddress(inParams
->qtype
) && !StringEndsWithDot(inParams
->qnameStr
) &&
335 (AlwaysAppendSearchDomains
|| DomainNameIsSingleLabel(&qname
)))
337 appendSearchDomains
= mDNStrue
;
341 appendSearchDomains
= mDNSfalse
;
343 QueryRecordOpParamsInit(&opParams
);
344 opParams
.requestID
= inParams
->requestID
;
345 opParams
.qname
= &qname
;
346 opParams
.qtype
= inParams
->qtype
;
347 opParams
.qclass
= inParams
->qclass
;
348 opParams
.interfaceID
= interfaceID
;
349 opParams
.appendSearchDomains
= appendSearchDomains
;
350 opParams
.effectivePID
= inParams
->effectivePID
;
351 opParams
.effectiveUUID
= inParams
->effectiveUUID
;
352 opParams
.peerUID
= inParams
->peerUID
;
353 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
354 opParams
.resolverUUID
= inParams
->resolverUUID
;
355 opParams
.customID
= inParams
->customID
;
356 opParams
.needEncryption
= inParams
->needEncryption
;
358 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
359 opParams
.peerAuditToken
= inParams
->peerAuditToken
;
360 opParams
.delegatorAuditToken
= inParams
->delegatorAuditToken
;
361 opParams
.isInAppBrowserRequest
= inParams
->isInAppBrowserRequest
;
363 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
364 // Query ends with ".local." and query for RRSIG or ANY type cannot be validated by DNSSEC even if the user sets the
365 // kDNSServiceFlagsEnableDNSSEC flag.
366 if (FLAGS_CONTAIN_DNSOK_BIT(inParams
->flags
) && is_eligible_for_dnssec(&qname
, inParams
->qtype
))
368 opParams
.flags
= inParams
->flags
| kDNSServiceFlagsReturnIntermediates
; // to handle CNAME reference
369 err
= create_dnssec_context_t(inRequest
, inParams
->requestID
, &qname
, inParams
->qtype
, inParams
->qclass
,
370 interfaceID
, -1, inParams
->flags
, appendSearchDomains
, inParams
->effectivePID
, inParams
->effectiveUUID
,
372 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
373 inParams
->peerAuditToken
, inParams
->delegatorAuditToken
,
375 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
376 mDNSNULL
, inParams
->needEncryption
, inParams
->customID
,
378 inResultHandler
, inResultContext
, mDNSNULL
, &dnssecContext
);
379 require_action(err
== mStatus_NoError
, exit
, log_debug("create_dnssec_context_t failed; error_description='%s'",
380 mStatusDescription(err
)));
382 err
= QueryRecordOpStart(&inRequest
->op
, &opParams
, query_record_result_reply_with_dnssec
, dnssecContext
);
384 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
386 opParams
.flags
= inParams
->flags
;
387 err
= QueryRecordOpStart(&inRequest
->op
, &opParams
, inResultHandler
, inResultContext
);
391 if (err
) QueryRecordClientRequestStop(inRequest
);
395 mDNSexport
void QueryRecordClientRequestStop(QueryRecordClientRequest
*inRequest
)
397 QueryRecordOpStop(&inRequest
->op
);
399 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
400 stop_dnssec_if_enable_dnssec(inRequest
);
403 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
404 if (inRequest
->op
.answered
)
406 DNSQuestion
*v4q
, *v6q
;
407 // If we are receiving positive answers, provide the hint to the upper layer. - Mohan
408 v4q
= (inRequest
->op
.q
.qtype
== kDNSType_A
) ? &inRequest
->op
.q
: mDNSNULL
;
409 v6q
= (inRequest
->op
.q
.qtype
== kDNSType_AAAA
) ? &inRequest
->op
.q
: mDNSNULL
;
410 mDNSPlatformTriggerDNSRetry(v4q
, v6q
);
415 mDNSexport
const domainname
* QueryRecordClientRequestGetQName(const QueryRecordClientRequest
*inRequest
)
417 return &inRequest
->op
.q
.qname
;
420 mDNSexport mDNSu16
QueryRecordClientRequestGetType(const QueryRecordClientRequest
*inRequest
)
422 return inRequest
->op
.q
.qtype
;
425 mDNSexport mDNSBool
QueryRecordClientRequestIsMulticast(QueryRecordClientRequest
*inRequest
)
427 return (QueryRecordOpIsMulticast(&inRequest
->op
) ? mDNStrue
: mDNSfalse
);
429 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
430 mDNSexport mStatus
QueryRecordOpStartForClientRequest(
431 QueryRecordOp
* inOp
,
433 const domainname
* inQName
,
436 mDNSInterfaceID inInterfaceID
,
439 mDNSBool inAppendSearchDomains
,
441 const mDNSu8 inUUID
[UUID_SIZE
],
443 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
444 const audit_token_t
* inPeerAuditTokenPtr
,
445 const audit_token_t
* inDelegateAuditTokenPtr
,
447 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
448 const mDNSu8 inResolverUUID
[UUID_SIZE
],
449 mDNSBool inNeedEncryption
,
450 const mdns_dns_service_id_t inCustomID
,
452 QueryRecordResultHandler inResultHandler
,
453 void * inResultContext
) {
454 QueryRecordOpParams opParams
;
455 QueryRecordOpParamsInit(&opParams
);
456 opParams
.requestID
= inReqID
;
457 opParams
.qname
= inQName
;
458 opParams
.qtype
= inQType
;
459 opParams
.qclass
= inQClass
;
460 opParams
.interfaceID
= inInterfaceID
;
461 opParams
.serviceID
= inServiceID
;
462 opParams
.flags
= inFlags
;
463 opParams
.appendSearchDomains
= inAppendSearchDomains
;
464 opParams
.effectivePID
= inPID
;
465 opParams
.effectiveUUID
= inUUID
;
466 opParams
.peerUID
= inUID
;
467 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
468 opParams
.resolverUUID
= inResolverUUID
;
469 opParams
.customID
= inCustomID
;
470 opParams
.needEncryption
= inNeedEncryption
;
472 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
473 opParams
.peerAuditToken
= inPeerAuditTokenPtr
;
474 opParams
.delegatorAuditToken
= inDelegateAuditTokenPtr
;
476 return QueryRecordOpStart(inOp
, &opParams
, inResultHandler
, inResultContext
);
479 mDNSexport
void QueryRecordOpStopForClientRequest(QueryRecordOp
*op
) {
480 QueryRecordOpStop(op
);
483 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
485 mDNSlocal mStatus
QueryRecordOpCreate(QueryRecordOp
**outOp
)
490 op
= (QueryRecordOp
*) mDNSPlatformMemAllocateClear(sizeof(*op
));
493 err
= mStatus_NoMemoryErr
;
497 err
= mStatus_NoError
;
503 mDNSlocal
void QueryRecordOpFree(QueryRecordOp
*operation
)
505 mDNSPlatformMemFree(operation
);
508 #define VALID_MSAD_SRV_TRANSPORT(T) \
509 (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp"))
510 #define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname)))
512 mDNSlocal mStatus
QueryRecordOpStart(QueryRecordOp
*inOp
, const QueryRecordOpParams
*inParams
,
513 QueryRecordResultHandler inResultHandler
, void *inResultContext
)
516 DNSQuestion
* const q
= &inOp
->q
;
519 // Save the original qname.
521 len
= DomainNameLength(inParams
->qname
);
522 inOp
->qname
= (domainname
*) mDNSPlatformMemAllocate(len
);
525 err
= mStatus_NoMemoryErr
;
528 mDNSPlatformMemCopy(inOp
->qname
, inParams
->qname
, len
);
530 inOp
->interfaceID
= inParams
->interfaceID
;
531 inOp
->reqID
= inParams
->requestID
;
532 inOp
->resultHandler
= inResultHandler
;
533 inOp
->resultContext
= inResultContext
;
535 // Set up DNSQuestion.
537 if (EnableAllowExpired
&& (inParams
->flags
& kDNSServiceFlagsAllowExpiredAnswers
))
539 q
->allowExpired
= AllowExpired_AllowExpiredAnswers
;
543 q
->allowExpired
= AllowExpired_None
;
545 q
->ServiceID
= inParams
->serviceID
;
546 #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
547 q
->inAppBrowserRequest
= inParams
->isInAppBrowserRequest
;
548 if (inParams
->peerAuditToken
)
550 q
->peerAuditToken
= *inParams
->peerAuditToken
;
552 if (inParams
->delegatorAuditToken
)
554 q
->delegateAuditToken
= *inParams
->delegatorAuditToken
;
557 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
558 if (inParams
->resolverUUID
)
560 mDNSPlatformMemCopy(q
->ResolverUUID
, inParams
->resolverUUID
, UUID_SIZE
);
563 q
->InterfaceID
= inParams
->interfaceID
;
564 q
->flags
= inParams
->flags
;
565 AssignDomainName(&q
->qname
, inParams
->qname
);
566 q
->qtype
= inParams
->qtype
;
567 q
->qclass
= inParams
->qclass
;
568 q
->LongLived
= (inParams
->flags
& kDNSServiceFlagsLongLivedQuery
) ? mDNStrue
: mDNSfalse
;
569 q
->ForceMCast
= (inParams
->flags
& kDNSServiceFlagsForceMulticast
) ? mDNStrue
: mDNSfalse
;
570 q
->ReturnIntermed
= (inParams
->flags
& kDNSServiceFlagsReturnIntermediates
) ? mDNStrue
: mDNSfalse
;
571 q
->SuppressUnusable
= (inParams
->flags
& kDNSServiceFlagsSuppressUnusable
) ? mDNStrue
: mDNSfalse
;
572 q
->TimeoutQuestion
= (inParams
->flags
& kDNSServiceFlagsTimeout
) ? mDNStrue
: mDNSfalse
;
573 q
->UseBackgroundTraffic
= (inParams
->flags
& kDNSServiceFlagsBackgroundTrafficClass
) ? mDNStrue
: mDNSfalse
;
574 q
->AppendSearchDomains
= inParams
->appendSearchDomains
;
575 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
576 q
->RequireEncryption
= inParams
->needEncryption
;
577 q
->CustomID
= inParams
->customID
;
579 q
->InitialCacheMiss
= mDNSfalse
;
581 #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
582 err
= initialize_dnssec_status_t(&q
->DNSSECStatus
, inParams
->qname
, inParams
->qtype
, inParams
->flags
, inResultContext
);
583 require_action(err
== mStatus_NoError
, exit
, log_debug("initialize_dnssec_status failed; error_description='%s'", mStatusDescription(err
)));
584 #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
586 q
->pid
= inParams
->effectivePID
;
587 if (inParams
->effectiveUUID
)
589 mDNSPlatformMemCopy(q
->uuid
, inParams
->effectiveUUID
, UUID_SIZE
);
591 q
->euid
= inParams
->peerUID
;
592 q
->request_id
= inParams
->requestID
;
593 q
->QuestionCallback
= QueryRecordOpCallback
;
594 q
->ResetHandler
= QueryRecordOpResetHandler
;
596 // For single label queries that are not fully qualified, look at /etc/hosts, cache and try search domains before trying
597 // them on the wire as a single label query. - Mohan
599 if (q
->AppendSearchDomains
&& DomainNameIsSingleLabel(inOp
->qname
)) q
->InterfaceID
= mDNSInterface_LocalOnly
;
600 err
= QueryRecordOpStartQuestion(inOp
, q
);
603 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
604 if (callExternalHelpers(q
->InterfaceID
, &q
->qname
, q
->flags
))
606 external_start_browsing_for_service(q
->InterfaceID
, &q
->qname
, q
->qtype
, q
->flags
, q
->pid
);
610 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
611 if ((RecordTypeIsAddress(q
->qtype
) || VALID_MSAD_SRV(&inOp
->q
)) && !q
->ForceMCast
&&
612 SameDomainLabel(LastLabel(&q
->qname
), (const mDNSu8
*)&localdomain
))
616 q2
= (DNSQuestion
*) mDNSPlatformMemAllocate((mDNSu32
)sizeof(*inOp
->q2
));
619 err
= mStatus_NoMemoryErr
;
625 q2
->IsUnicastDotLocal
= mDNStrue
;
627 if ((CountLabels(&q2
->qname
) == 2) && !SameDomainName(&q2
->qname
, &ActiveDirectoryPrimaryDomain
)
628 && !DomainNameIsInSearchList(&q2
->qname
, mDNSfalse
))
630 inOp
->q2Type
= q2
->qtype
;
631 inOp
->q2LongLived
= q2
->LongLived
;
632 inOp
->q2ReturnIntermed
= q2
->ReturnIntermed
;
633 inOp
->q2TimeoutQuestion
= q2
->TimeoutQuestion
;
634 inOp
->q2AppendSearchDomains
= q2
->AppendSearchDomains
;
636 AssignDomainName(&q2
->qname
, &localdomain
);
637 q2
->qtype
= kDNSType_SOA
;
638 q2
->LongLived
= mDNSfalse
;
639 q2
->ReturnIntermed
= mDNStrue
;
640 q2
->TimeoutQuestion
= mDNSfalse
;
641 q2
->AppendSearchDomains
= mDNSfalse
;
644 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
645 "[R%u] QueryRecordOpStart: starting parallel unicast query for " PRI_DM_NAME
" " PUB_S
,
646 inOp
->reqID
, DM_NAME_PARAM(&q2
->qname
), DNSTypeName(q2
->qtype
));
648 err
= QueryRecordOpStartQuestion(inOp
, q2
);
652 err
= mStatus_NoError
;
655 if (err
) QueryRecordOpStop(inOp
);
659 mDNSlocal
void QueryRecordOpStop(QueryRecordOp
*op
)
661 if (op
->q
.QuestionContext
)
663 QueryRecordOpStopQuestion(&op
->q
);
664 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
665 if (callExternalHelpers(op
->q
.InterfaceID
, op
->qname
, op
->q
.flags
))
667 external_stop_browsing_for_service(op
->q
.InterfaceID
, &op
->q
.qname
, op
->q
.qtype
, op
->q
.flags
, op
->q
.pid
);
673 mDNSPlatformMemFree(op
->qname
);
674 op
->qname
= mDNSNULL
;
676 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
679 if (op
->q2
->QuestionContext
) QueryRecordOpStopQuestion(op
->q2
);
680 mDNSPlatformMemFree(op
->q2
);
686 mDNSlocal mDNSBool
QueryRecordOpIsMulticast(const QueryRecordOp
*op
)
688 return ((mDNSOpaque16IsZero(op
->q
.TargetQID
) && (op
->q
.ThisQInterval
> 0)) ? mDNStrue
: mDNSfalse
);
691 // GetTimeNow is a callback-safe alternative to mDNS_TimeNow(), which expects to be called with m->mDNS_busy == 0.
692 mDNSlocal mDNSs32
GetTimeNow(mDNS
*m
)
701 mDNSlocal
void QueryRecordOpCallback(mDNS
*m
, DNSQuestion
*inQuestion
, const ResourceRecord
*inAnswer
, QC_result inAddRecord
)
704 QueryRecordOp
*const op
= (QueryRecordOp
*)inQuestion
->QuestionContext
;
705 const domainname
* domain
;
707 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
708 if ((inQuestion
== op
->q2
) && (inQuestion
->qtype
== kDNSType_SOA
))
710 DNSQuestion
* const q2
= op
->q2
;
712 if (inAnswer
->rrtype
!= kDNSType_SOA
) goto exit
;
713 QueryRecordOpStopQuestion(q2
);
715 // Restore DNSQuestion variables that were modified for the SOA query.
717 q2
->qtype
= op
->q2Type
;
718 q2
->LongLived
= op
->q2LongLived
;
719 q2
->ReturnIntermed
= op
->q2ReturnIntermed
;
720 q2
->TimeoutQuestion
= op
->q2TimeoutQuestion
;
721 q2
->AppendSearchDomains
= op
->q2AppendSearchDomains
;
723 if (inAnswer
->RecordType
!= kDNSRecordTypePacketNegative
)
725 QueryRecordOpRestartUnicastQuestion(op
, q2
, mDNSNULL
);
727 else if (q2
->AppendSearchDomains
)
729 domain
= NextSearchDomain(op
);
730 if (domain
) QueryRecordOpRestartUnicastQuestion(op
, q2
, domain
);
736 if (inAddRecord
== QC_suppressed
)
738 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEBUG
,
739 "[R%u] QueryRecordOpCallback: Suppressed question " PRI_DM_NAME
" (" PUB_S
")",
740 op
->reqID
, DM_NAME_PARAM(&inQuestion
->qname
), DNSTypeName(inQuestion
->qtype
));
742 resultErr
= kDNSServiceErr_NoSuchRecord
;
744 else if (inAnswer
->RecordType
== kDNSRecordTypePacketNegative
)
746 if (inQuestion
->TimeoutQuestion
&& ((GetTimeNow(m
) - inQuestion
->StopTime
) >= 0))
748 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
749 "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME
" (" PUB_S
") timing out, InterfaceID %p",
750 op
->reqID
, DM_NAME_PARAM(&inQuestion
->qname
), DNSTypeName(inQuestion
->qtype
),
751 inQuestion
->InterfaceID
);
752 resultErr
= kDNSServiceErr_Timeout
;
756 if (inQuestion
->AppendSearchDomains
&& (op
->searchListIndex
>= 0) && inAddRecord
)
758 domain
= NextSearchDomain(op
);
759 if (domain
|| DomainNameIsSingleLabel(op
->qname
))
761 QueryRecordOpStopQuestion(inQuestion
);
762 QueryRecordOpRestartUnicastQuestion(op
, inQuestion
, domain
);
766 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
767 if (!inAnswer
->InterfaceID
&& IsLocalDomain(inAnswer
->name
))
769 if ((RecordTypeIsAddress(inQuestion
->qtype
) &&
770 (inAnswer
->negativeRecordType
== kNegativeRecordType_NoData
)) ||
771 DomainNameIsInSearchList(&inQuestion
->qname
, mDNStrue
))
773 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
774 "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME
" (" PUB_S
") answering local with negative unicast response",
775 op
->reqID
, DM_NAME_PARAM(&inQuestion
->qname
), DNSTypeName(inQuestion
->qtype
));
783 resultErr
= kDNSServiceErr_NoSuchRecord
;
788 resultErr
= kDNSServiceErr_NoError
;
791 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
792 if ((resultErr
!= kDNSServiceErr_Timeout
) && (inAddRecord
== QC_add
))
794 op
->answered
= mDNStrue
;
798 if (op
->resultHandler
) op
->resultHandler(m
, inQuestion
, inAnswer
, inAddRecord
, resultErr
, op
->resultContext
);
799 if (resultErr
== kDNSServiceErr_Timeout
) QueryRecordOpStopQuestion(inQuestion
);
801 #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
802 NotifyWebContentFilter(inAnswer
, inQuestion
->euid
);
809 mDNSlocal
void QueryRecordOpResetHandler(DNSQuestion
*inQuestion
)
811 QueryRecordOp
*const op
= (QueryRecordOp
*)inQuestion
->QuestionContext
;
813 AssignDomainName(&inQuestion
->qname
, op
->qname
);
814 if (inQuestion
->AppendSearchDomains
&& DomainNameIsSingleLabel(op
->qname
))
816 inQuestion
->InterfaceID
= mDNSInterface_LocalOnly
;
820 inQuestion
->InterfaceID
= op
->interfaceID
;
822 op
->searchListIndex
= 0;
825 mDNSlocal mStatus
QueryRecordOpStartQuestion(QueryRecordOp
*inOp
, DNSQuestion
*inQuestion
)
829 inQuestion
->QuestionContext
= inOp
;
830 err
= mDNS_StartQuery(&mDNSStorage
, inQuestion
);
833 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
834 "[R%u] ERROR: QueryRecordOpStartQuestion mDNS_StartQuery for " PRI_DM_NAME
" " PUB_S
" failed with error %d",
835 inOp
->reqID
, DM_NAME_PARAM(&inQuestion
->qname
), DNSTypeName(inQuestion
->qtype
), err
);
836 inQuestion
->QuestionContext
= mDNSNULL
;
841 mDNSlocal mStatus
QueryRecordOpStopQuestion(DNSQuestion
*inQuestion
)
845 err
= mDNS_StopQuery(&mDNSStorage
, inQuestion
);
846 inQuestion
->QuestionContext
= mDNSNULL
;
850 mDNSlocal mStatus
QueryRecordOpRestartUnicastQuestion(QueryRecordOp
*inOp
, DNSQuestion
*inQuestion
,
851 const domainname
*inSearchDomain
)
855 inQuestion
->InterfaceID
= inOp
->interfaceID
;
856 AssignDomainName(&inQuestion
->qname
, inOp
->qname
);
857 if (inSearchDomain
) AppendDomainName(&inQuestion
->qname
, inSearchDomain
);
858 if (SameDomainLabel(LastLabel(&inQuestion
->qname
), (const mDNSu8
*)&localdomain
))
860 inQuestion
->IsUnicastDotLocal
= mDNStrue
;
864 inQuestion
->IsUnicastDotLocal
= mDNSfalse
;
866 err
= QueryRecordOpStartQuestion(inOp
, inQuestion
);
870 mDNSlocal mStatus
InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex
, mDNSInterfaceID
*outInterfaceID
)
873 mDNSInterfaceID interfaceID
;
875 interfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, inInterfaceIndex
);
877 #if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
878 // The request is scoped to a specific interface index, but the interface is not currently in our list.
879 if ((inInterfaceIndex
!= kDNSServiceInterfaceIndexAny
) && (interfaceID
== mDNSInterface_Any
))
881 static dispatch_once_t getLoopbackIndexOnce
= 0;
882 static mDNSu32 loopbackIndex
= 0;
884 dispatch_once(&getLoopbackIndexOnce
,
886 loopbackIndex
= if_nametoindex("lo0");
889 // If it's one of the specially defined inteface index values, just return an error. Also, caller should return an
890 // error immediately if lo0 is not configured into the current active interfaces. See <rdar://problem/21967160>.
891 if ((inInterfaceIndex
== kDNSServiceInterfaceIndexLocalOnly
) ||
892 (inInterfaceIndex
== kDNSServiceInterfaceIndexUnicast
) ||
893 (inInterfaceIndex
== kDNSServiceInterfaceIndexP2P
) ||
894 (inInterfaceIndex
== kDNSServiceInterfaceIndexBLE
) ||
895 (inInterfaceIndex
== loopbackIndex
))
897 LogInfo("ERROR: bad interfaceIndex %d", inInterfaceIndex
);
898 err
= mStatus_BadParamErr
;
902 // Otherwise, use the specified interface index value and the request will be applied to that interface when it
904 interfaceID
= (mDNSInterfaceID
)(uintptr_t)inInterfaceIndex
;
905 LogInfo("Query pending for interface index %d", inInterfaceIndex
);
909 *outInterfaceID
= interfaceID
;
910 err
= mStatus_NoError
;
912 #if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
918 mDNSlocal mDNSBool
DomainNameIsSingleLabel(const domainname
*inName
)
920 const mDNSu8
*const label
= inName
->c
;
921 return (((label
[0] != 0) && (label
[1 + label
[0]] == 0)) ? mDNStrue
: mDNSfalse
);
924 mDNSlocal mDNSBool
StringEndsWithDot(const char *inString
)
930 // Loop invariant: escapeCount is the number of consecutive escape characters that immediately precede *ptr.
931 // - If escapeCount is even, then *ptr is immediately preceded by escapeCount / 2 consecutive literal backslash
932 // characters, so *ptr is not escaped.
933 // - If escapeCount is odd, then *ptr is immediately preceded by (escapeCount - 1) / 2 consecutive literal backslash
934 // characters followed by an escape character, so *ptr is escaped.
937 for (ptr
= inString
; *ptr
!= '\0'; ptr
++)
945 if ((*ptr
== '.') && (ptr
[1] == '\0'))
947 if ((escapeCount
% 2) == 0) result
= mDNStrue
;
956 mDNSlocal
const domainname
* NextSearchDomain(QueryRecordOp
*inOp
)
958 const domainname
* domain
;
960 while ((domain
= uDNS_GetNextSearchDomain(inOp
->interfaceID
, &inOp
->searchListIndex
, mDNSfalse
)) != mDNSNULL
)
962 if ((DomainNameLength(inOp
->qname
) - 1 + DomainNameLength(domain
)) <= MAX_DOMAIN_NAME
) break;
964 if (!domain
) inOp
->searchListIndex
= -1;
968 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
969 mDNSlocal mDNSBool
DomainNameIsInSearchList(const domainname
*inName
, mDNSBool inExcludeLocal
)
971 const SearchListElem
* item
;
972 int labelCount
, domainLabelCount
;
974 labelCount
= CountLabels(inName
);
975 for (item
= SearchList
; item
; item
= item
->next
)
977 if (inExcludeLocal
&& SameDomainName(&item
->domain
, &localdomain
)) continue;
978 domainLabelCount
= CountLabels(&item
->domain
);
979 if (labelCount
>= domainLabelCount
)
981 if (SameDomainName(&item
->domain
, SkipLeadingLabels(inName
, (labelCount
- domainLabelCount
))))
991 #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
992 mDNSlocal
void NotifyWebContentFilter(const ResourceRecord
*inAnswer
, uid_t inUID
)
994 if (WCFIsServerRunning
)
996 const mDNS
*const m
= &mDNSStorage
;
998 if (WCFIsServerRunning(m
->WCF
) && inAnswer
->rdlength
!= 0)
1000 struct sockaddr_storage addr
;
1002 if (inAnswer
->rrtype
== kDNSType_A
|| inAnswer
->rrtype
== kDNSType_AAAA
)
1004 if (inAnswer
->rrtype
== kDNSType_A
)
1006 struct sockaddr_in
*const sin
= (struct sockaddr_in
*)&addr
;
1008 // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
1009 // sin->sin_addr.s_addr = inAnswer->rdata->u.ipv4.NotAnInteger;
1010 if (!putRData(mDNSNULL
, (mDNSu8
*)&sin
->sin_addr
, (mDNSu8
*)(&sin
->sin_addr
+ sizeof(mDNSv4Addr
)), inAnswer
))
1011 LogMsg("NotifyWebContentFilter: WCF AF_INET putRData failed");
1014 addr
.ss_len
= sizeof (struct sockaddr_in
);
1015 addr
.ss_family
= AF_INET
;
1018 else if (inAnswer
->rrtype
== kDNSType_AAAA
)
1020 struct sockaddr_in6
*const sin6
= (struct sockaddr_in6
*)&addr
;
1021 sin6
->sin6_port
= 0;
1022 // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
1023 // sin6->sin6_addr.__u6_addr.__u6_addr32[0] = inAnswer->rdata->u.ipv6.l[0];
1024 // sin6->sin6_addr.__u6_addr.__u6_addr32[1] = inAnswer->rdata->u.ipv6.l[1];
1025 // sin6->sin6_addr.__u6_addr.__u6_addr32[2] = inAnswer->rdata->u.ipv6.l[2];
1026 // sin6->sin6_addr.__u6_addr.__u6_addr32[3] = inAnswer->rdata->u.ipv6.l[3];
1027 if (!putRData(mDNSNULL
, (mDNSu8
*)&sin6
->sin6_addr
, (mDNSu8
*)(&sin6
->sin6_addr
+ sizeof(mDNSv6Addr
)), inAnswer
))
1028 LogMsg("NotifyWebContentFilter: WCF AF_INET6 putRData failed");
1031 addr
.ss_len
= sizeof (struct sockaddr_in6
);
1032 addr
.ss_family
= AF_INET6
;
1037 char name
[MAX_ESCAPED_DOMAIN_NAME
];
1038 ConvertDomainNameToCString(inAnswer
->name
, name
);
1040 debugf("NotifyWebContentFilter: Name %s, uid %u, addr length %d", name
, inUID
, addr
.ss_len
);
1041 if (WCFNameResolvesToAddr
)
1043 WCFNameResolvesToAddr(m
->WCF
, name
, (struct sockaddr
*)&addr
, inUID
);
1047 else if (inAnswer
->rrtype
== kDNSType_CNAME
)
1050 char name
[MAX_ESCAPED_DOMAIN_NAME
];
1051 char cname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
1053 if (!putRData(mDNSNULL
, cname
.c
, (mDNSu8
*)(cname
.c
+ MAX_DOMAIN_NAME
), inAnswer
))
1054 LogMsg("NotifyWebContentFilter: WCF CNAME putRData failed");
1057 ConvertDomainNameToCString(inAnswer
->name
, name
);
1058 ConvertDomainNameToCString(&cname
, cname_cstr
);
1059 if (WCFNameResolvesToAddr
)
1061 WCFNameResolvesToName(m
->WCF
, name
, cname_cstr
, inUID
);