2 * Copyright (c) 2018-2019 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, D2D)
26 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
27 #include "mDNSMacOSX.h"
30 #if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
31 #include <dispatch/dispatch.h>
35 #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
36 #include <WebFilterDNS/WebFilterDNS.h>
38 int WCFIsServerRunning(WCFConnection
*conn
) __attribute__((weak_import
));
39 int WCFNameResolvesToAddr(WCFConnection
*conn
, char* domainName
, struct sockaddr
* address
, uid_t userid
) __attribute__((weak_import
));
40 int WCFNameResolvesToName(WCFConnection
*conn
, char* fromName
, char* toName
, uid_t userid
) __attribute__((weak_import
));
43 #define RecordTypeIsAddress(TYPE) (((TYPE) == kDNSType_A) || ((TYPE) == kDNSType_AAAA))
45 extern mDNS mDNSStorage
;
46 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
47 extern domainname ActiveDirectoryPrimaryDomain
;
50 // Normally we append search domains only for queries with a single label that are not fully qualified. This can be
51 // overridden to apply search domains for queries (that are not fully qualified) with any number of labels e.g., moon,
52 // moon.cs, moon.cs.be, etc. - Mohan
53 mDNSBool AlwaysAppendSearchDomains
= mDNSfalse
;
55 // Control enabling optimistic DNS - Phil
56 mDNSBool EnableAllowExpired
= mDNStrue
;
58 mDNSlocal mStatus
QueryRecordOpCreate(QueryRecordOp
**outOp
);
59 mDNSlocal
void QueryRecordOpFree(QueryRecordOp
*operation
);
60 mDNSlocal mStatus
QueryRecordOpStart(QueryRecordOp
*inOp
, mDNSu32 inReqID
, const domainname
*inQName
, mDNSu16 inQType
,
61 mDNSu16 inQClass
, mDNSInterfaceID inInterfaceID
, mDNSs32 inServiceID
, mDNSu32 inFlags
, mDNSBool inAppendSearchDomains
,
62 mDNSs32 inPID
, const mDNSu8 inUUID
[UUID_SIZE
], mDNSu32 inUID
, QueryRecordResultHandler inResultHandler
,
63 void *inResultContext
);
64 mDNSlocal
void QueryRecordOpStop(QueryRecordOp
*op
);
65 mDNSlocal mDNSBool
QueryRecordOpIsMulticast(const QueryRecordOp
*op
);
66 mDNSlocal
void QueryRecordOpCallback(mDNS
*m
, DNSQuestion
*inQuestion
, const ResourceRecord
*inAnswer
,
67 QC_result inAddRecord
);
68 mDNSlocal
void QueryRecordOpResetHandler(DNSQuestion
*inQuestion
);
69 mDNSlocal mStatus
QueryRecordOpStartQuestion(QueryRecordOp
*inOp
, DNSQuestion
*inQuestion
);
70 mDNSlocal mStatus
QueryRecordOpStopQuestion(DNSQuestion
*inQuestion
);
71 mDNSlocal mStatus
QueryRecordOpRestartUnicastQuestion(QueryRecordOp
*inOp
, DNSQuestion
*inQuestion
,
72 const domainname
*inSearchDomain
);
73 mDNSlocal mStatus
InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex
, mDNSInterfaceID
*outInterfaceID
);
74 mDNSlocal mDNSBool
DomainNameIsSingleLabel(const domainname
*inName
);
75 mDNSlocal mDNSBool
StringEndsWithDot(const char *inString
);
76 mDNSlocal
const domainname
* NextSearchDomain(QueryRecordOp
*inOp
);
77 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
78 mDNSlocal mDNSBool
DomainNameIsInSearchList(const domainname
*domain
, mDNSBool inExcludeLocal
);
80 #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
81 mDNSlocal
void NotifyWebContentFilter(const ResourceRecord
*inAnswer
, uid_t inUID
);
84 mDNSexport mStatus
GetAddrInfoClientRequestStart(GetAddrInfoClientRequest
*inRequest
, mDNSu32 inReqID
,
85 const char *inHostnameStr
, mDNSu32 inInterfaceIndex
, DNSServiceFlags inFlags
, mDNSu32 inProtocols
, mDNSs32 inPID
,
86 const mDNSu8 inUUID
[UUID_SIZE
], mDNSu32 inUID
, QueryRecordResultHandler inResultHandler
,
87 void *inResultContext
)
91 mDNSBool appendSearchDomains
;
92 mDNSInterfaceID interfaceID
;
93 DNSServiceFlags flags
;
96 if (!MakeDomainNameFromDNSNameString(&hostname
, inHostnameStr
))
98 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
99 "[R%u] ERROR: bad hostname '" PRI_S
"'", inReqID
, inHostnameStr
);
100 err
= mStatus_BadParamErr
;
104 if (inProtocols
& ~(kDNSServiceProtocol_IPv4
|kDNSServiceProtocol_IPv6
))
106 err
= mStatus_BadParamErr
;
113 flags
|= kDNSServiceFlagsSuppressUnusable
;
114 inRequest
->protocols
= kDNSServiceProtocol_IPv4
| kDNSServiceProtocol_IPv6
;
118 inRequest
->protocols
= inProtocols
;
121 if (flags
& kDNSServiceFlagsServiceIndex
)
123 // NOTE: kDNSServiceFlagsServiceIndex flag can only be set for DNSServiceGetAddrInfo()
124 LogInfo("GetAddrInfoClientRequestStart: kDNSServiceFlagsServiceIndex is SET by the client");
126 // If kDNSServiceFlagsServiceIndex is SET, interpret the interfaceID as the serviceId and set the interfaceID to 0.
127 serviceID
= (mDNSs32
)inInterfaceIndex
;
128 interfaceID
= mDNSNULL
;
133 err
= InterfaceIndexToInterfaceID(inInterfaceIndex
, &interfaceID
);
136 inRequest
->interfaceID
= interfaceID
;
138 if (!StringEndsWithDot(inHostnameStr
) && (AlwaysAppendSearchDomains
|| DomainNameIsSingleLabel(&hostname
)))
140 appendSearchDomains
= mDNStrue
;
144 appendSearchDomains
= mDNSfalse
;
147 if (inRequest
->protocols
& kDNSServiceProtocol_IPv6
)
149 err
= QueryRecordOpCreate(&inRequest
->op6
);
152 err
= QueryRecordOpStart(inRequest
->op6
, inReqID
, &hostname
, kDNSType_AAAA
, kDNSServiceClass_IN
,
153 inRequest
->interfaceID
, serviceID
, flags
, appendSearchDomains
, inPID
, inUUID
, inUID
, inResultHandler
,
158 if (inRequest
->protocols
& kDNSServiceProtocol_IPv4
)
160 err
= QueryRecordOpCreate(&inRequest
->op4
);
163 err
= QueryRecordOpStart(inRequest
->op4
, inReqID
, &hostname
, kDNSType_A
, kDNSServiceClass_IN
,
164 inRequest
->interfaceID
, serviceID
, flags
, appendSearchDomains
, inPID
, inUUID
, inUID
, inResultHandler
,
168 err
= mStatus_NoError
;
171 if (err
) GetAddrInfoClientRequestStop(inRequest
);
175 mDNSexport
void GetAddrInfoClientRequestStop(GetAddrInfoClientRequest
*inRequest
)
177 if (inRequest
->op4
) QueryRecordOpStop(inRequest
->op4
);
178 if (inRequest
->op6
) QueryRecordOpStop(inRequest
->op6
);
180 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
182 const QueryRecordOp
* const op4
= inRequest
->op4
;
183 const QueryRecordOp
* const op6
= inRequest
->op6
;
184 const DNSQuestion
* q4
= mDNSNULL
;
185 const DNSQuestion
* q6
= mDNSNULL
;
191 // If we have a v4 answer and if we timed out prematurely before, provide a trigger to the upper layer so
192 // that it can retry questions if needed. - Mohan
195 else if (op4
->q
.TimeoutQuestion
)
197 // If we are not delivering answers, we may be timing out prematurely. Note down the current state so that
198 // we know to retry when we see a valid response again. - Mohan
199 mDNSPlatformUpdateDNSStatus(&op4
->q
);
208 else if (op6
->q
.TimeoutQuestion
)
210 mDNSPlatformUpdateDNSStatus(&op6
->q
);
213 mDNSPlatformTriggerDNSRetry(q4
, q6
);
219 QueryRecordOpFree(inRequest
->op4
);
220 inRequest
->op4
= mDNSNULL
;
224 QueryRecordOpFree(inRequest
->op6
);
225 inRequest
->op6
= mDNSNULL
;
229 mDNSexport
const domainname
* GetAddrInfoClientRequestGetQName(const GetAddrInfoClientRequest
*inRequest
)
231 if (inRequest
->op4
) return &inRequest
->op4
->q
.qname
;
232 if (inRequest
->op6
) return &inRequest
->op6
->q
.qname
;
233 return (const domainname
*)"";
236 mDNSexport mDNSBool
GetAddrInfoClientRequestIsMulticast(const GetAddrInfoClientRequest
*inRequest
)
238 if ((inRequest
->op4
&& QueryRecordOpIsMulticast(inRequest
->op4
)) ||
239 (inRequest
->op6
&& QueryRecordOpIsMulticast(inRequest
->op6
)))
246 mDNSexport mStatus
QueryRecordClientRequestStart(QueryRecordClientRequest
*inRequest
, mDNSu32 inReqID
,
247 const char *inQNameStr
, mDNSu32 inInterfaceIndex
, DNSServiceFlags inFlags
, mDNSu16 inQType
, mDNSu16 inQClass
,
248 mDNSs32 inPID
, mDNSu8 inUUID
[UUID_SIZE
], mDNSu32 inUID
, QueryRecordResultHandler inResultHandler
, void *inResultContext
)
252 mDNSInterfaceID interfaceID
;
253 mDNSBool appendSearchDomains
;
255 err
= InterfaceIndexToInterfaceID(inInterfaceIndex
, &interfaceID
);
258 if (!MakeDomainNameFromDNSNameString(&qname
, inQNameStr
))
260 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
261 "[R%u] ERROR: bad domain name '" PRI_S
"'", inReqID
, inQNameStr
);
262 err
= mStatus_BadParamErr
;
266 if (RecordTypeIsAddress(inQType
) && !StringEndsWithDot(inQNameStr
) &&
267 (AlwaysAppendSearchDomains
|| DomainNameIsSingleLabel(&qname
)))
269 appendSearchDomains
= mDNStrue
;
273 appendSearchDomains
= mDNSfalse
;
276 err
= QueryRecordOpStart(&inRequest
->op
, inReqID
, &qname
, inQType
, inQClass
, interfaceID
, -1, inFlags
,
277 appendSearchDomains
, inPID
, inUUID
, inUID
, inResultHandler
, inResultContext
);
280 if (err
) QueryRecordClientRequestStop(inRequest
);
284 mDNSexport
void QueryRecordClientRequestStop(QueryRecordClientRequest
*inRequest
)
286 QueryRecordOpStop(&inRequest
->op
);
287 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
288 if (inRequest
->op
.answered
)
290 DNSQuestion
*v4q
, *v6q
;
291 // If we are receiving positive answers, provide the hint to the upper layer. - Mohan
292 v4q
= (inRequest
->op
.q
.qtype
== kDNSType_A
) ? &inRequest
->op
.q
: mDNSNULL
;
293 v6q
= (inRequest
->op
.q
.qtype
== kDNSType_AAAA
) ? &inRequest
->op
.q
: mDNSNULL
;
294 mDNSPlatformTriggerDNSRetry(v4q
, v6q
);
299 mDNSexport
const domainname
* QueryRecordClientRequestGetQName(const QueryRecordClientRequest
*inRequest
)
301 return &inRequest
->op
.q
.qname
;
304 mDNSexport mDNSu16
QueryRecordClientRequestGetType(const QueryRecordClientRequest
*inRequest
)
306 return inRequest
->op
.q
.qtype
;
309 mDNSexport mDNSBool
QueryRecordClientRequestIsMulticast(QueryRecordClientRequest
*inRequest
)
311 return (QueryRecordOpIsMulticast(&inRequest
->op
) ? mDNStrue
: mDNSfalse
);
314 mDNSlocal mStatus
QueryRecordOpCreate(QueryRecordOp
**outOp
)
319 op
= (QueryRecordOp
*) mDNSPlatformMemAllocateClear(sizeof(*op
));
322 err
= mStatus_NoMemoryErr
;
326 err
= mStatus_NoError
;
332 mDNSlocal
void QueryRecordOpFree(QueryRecordOp
*operation
)
334 mDNSPlatformMemFree(operation
);
337 #define VALID_MSAD_SRV_TRANSPORT(T) \
338 (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp"))
339 #define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname)))
341 mDNSlocal mStatus
QueryRecordOpStart(QueryRecordOp
*inOp
, mDNSu32 inReqID
, const domainname
*inQName
, mDNSu16 inQType
,
342 mDNSu16 inQClass
, mDNSInterfaceID inInterfaceID
, mDNSs32 inServiceID
, mDNSu32 inFlags
, mDNSBool inAppendSearchDomains
,
343 mDNSs32 inPID
, const mDNSu8 inUUID
[UUID_SIZE
], mDNSu32 inUID
, QueryRecordResultHandler inResultHandler
,
344 void *inResultContext
)
347 DNSQuestion
* const q
= &inOp
->q
;
350 // Save the original qname.
352 len
= DomainNameLength(inQName
);
353 inOp
->qname
= (domainname
*) mDNSPlatformMemAllocate(len
);
356 err
= mStatus_NoMemoryErr
;
359 mDNSPlatformMemCopy(inOp
->qname
, inQName
, len
);
361 inOp
->interfaceID
= inInterfaceID
;
362 inOp
->reqID
= inReqID
;
363 inOp
->resultHandler
= inResultHandler
;
364 inOp
->resultContext
= inResultContext
;
366 // Set up DNSQuestion.
368 if (EnableAllowExpired
&& (inFlags
& kDNSServiceFlagsAllowExpiredAnswers
))
370 q
->allowExpired
= AllowExpired_AllowExpiredAnswers
;
374 q
->allowExpired
= AllowExpired_None
;
376 q
->ServiceID
= inServiceID
;
377 q
->InterfaceID
= inInterfaceID
;
379 AssignDomainName(&q
->qname
, inQName
);
381 q
->qclass
= inQClass
;
382 q
->LongLived
= (inFlags
& kDNSServiceFlagsLongLivedQuery
) ? mDNStrue
: mDNSfalse
;
383 q
->ForceMCast
= (inFlags
& kDNSServiceFlagsForceMulticast
) ? mDNStrue
: mDNSfalse
;
384 q
->ReturnIntermed
= (inFlags
& kDNSServiceFlagsReturnIntermediates
) ? mDNStrue
: mDNSfalse
;
385 q
->SuppressUnusable
= (inFlags
& kDNSServiceFlagsSuppressUnusable
) ? mDNStrue
: mDNSfalse
;
386 q
->TimeoutQuestion
= (inFlags
& kDNSServiceFlagsTimeout
) ? mDNStrue
: mDNSfalse
;
387 q
->UseBackgroundTraffic
= (inFlags
& kDNSServiceFlagsBackgroundTrafficClass
) ? mDNStrue
: mDNSfalse
;
388 q
->AppendSearchDomains
= inAppendSearchDomains
;
389 q
->InitialCacheMiss
= mDNSfalse
;
391 // Turn off dnssec validation for local domains and Question Types: RRSIG/ANY(ANY Type is not supported yet) - Mohan
393 q
->ValidationRequired
= DNSSEC_VALIDATION_NONE
;
394 if (!IsLocalDomain(&q
->qname
) && (inQType
!= kDNSServiceType_RRSIG
) && (inQType
!= kDNSServiceType_ANY
))
396 if (inFlags
& kDNSServiceFlagsValidate
)
398 q
->ValidationRequired
= DNSSEC_VALIDATION_SECURE
;
399 q
->AppendSearchDomains
= mDNSfalse
;
401 else if (inFlags
& kDNSServiceFlagsValidateOptional
)
403 q
->ValidationRequired
= DNSSEC_VALIDATION_SECURE_OPTIONAL
;
408 if (inUUID
) mDNSPlatformMemCopy(q
->uuid
, inUUID
, UUID_SIZE
);
410 q
->request_id
= inReqID
;
411 q
->QuestionCallback
= QueryRecordOpCallback
;
412 q
->ResetHandler
= QueryRecordOpResetHandler
;
414 // For single label queries that are not fully qualified, look at /etc/hosts, cache and try search domains before trying
415 // them on the wire as a single label query. - Mohan
417 if (q
->AppendSearchDomains
&& DomainNameIsSingleLabel(inOp
->qname
)) q
->InterfaceID
= mDNSInterface_LocalOnly
;
418 err
= QueryRecordOpStartQuestion(inOp
, q
);
421 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
422 if (callExternalHelpers(q
->InterfaceID
, &q
->qname
, q
->flags
))
424 external_start_browsing_for_service(q
->InterfaceID
, &q
->qname
, q
->qtype
, q
->flags
);
428 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
429 if ((RecordTypeIsAddress(q
->qtype
) || VALID_MSAD_SRV(&inOp
->q
)) && !q
->ForceMCast
&&
430 SameDomainLabel(LastLabel(&q
->qname
), (const mDNSu8
*)&localdomain
))
434 q2
= (DNSQuestion
*) mDNSPlatformMemAllocate((mDNSu32
)sizeof(*inOp
->q2
));
437 err
= mStatus_NoMemoryErr
;
443 q2
->IsUnicastDotLocal
= mDNStrue
;
445 if ((CountLabels(&q2
->qname
) == 2) && !SameDomainName(&q2
->qname
, &ActiveDirectoryPrimaryDomain
)
446 && !DomainNameIsInSearchList(&q2
->qname
, mDNSfalse
))
448 inOp
->q2Type
= q2
->qtype
;
449 inOp
->q2LongLived
= q2
->LongLived
;
450 inOp
->q2ReturnIntermed
= q2
->ReturnIntermed
;
451 inOp
->q2TimeoutQuestion
= q2
->TimeoutQuestion
;
452 inOp
->q2AppendSearchDomains
= q2
->AppendSearchDomains
;
454 AssignDomainName(&q2
->qname
, &localdomain
);
455 q2
->qtype
= kDNSType_SOA
;
456 q2
->LongLived
= mDNSfalse
;
457 q2
->ReturnIntermed
= mDNStrue
;
458 q2
->TimeoutQuestion
= mDNSfalse
;
459 q2
->AppendSearchDomains
= mDNSfalse
;
462 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
463 "[R%u] QueryRecordOpStart: starting parallel unicast query for " PRI_DM_NAME
" " PUB_S
,
464 inOp
->reqID
, DM_NAME_PARAM(q2
->qname
.c
), DNSTypeName(q2
->qtype
));
466 err
= QueryRecordOpStartQuestion(inOp
, q2
);
470 err
= mStatus_NoError
;
473 if (err
) QueryRecordOpStop(inOp
);
477 mDNSlocal
void QueryRecordOpStop(QueryRecordOp
*op
)
479 if (op
->q
.QuestionContext
)
481 QueryRecordOpStopQuestion(&op
->q
);
482 #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
483 if (callExternalHelpers(op
->q
.InterfaceID
, op
->qname
, op
->q
.flags
))
485 external_stop_browsing_for_service(op
->q
.InterfaceID
, &op
->q
.qname
, op
->q
.qtype
, op
->q
.flags
);
491 mDNSPlatformMemFree(op
->qname
);
492 op
->qname
= mDNSNULL
;
494 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
497 if (op
->q2
->QuestionContext
) QueryRecordOpStopQuestion(op
->q2
);
498 mDNSPlatformMemFree(op
->q2
);
504 mDNSlocal mDNSBool
QueryRecordOpIsMulticast(const QueryRecordOp
*op
)
506 return ((mDNSOpaque16IsZero(op
->q
.TargetQID
) && (op
->q
.ThisQInterval
> 0)) ? mDNStrue
: mDNSfalse
);
509 // GetTimeNow is a callback-safe alternative to mDNS_TimeNow(), which expects to be called with m->mDNS_busy == 0.
510 mDNSlocal mDNSs32
GetTimeNow(mDNS
*m
)
519 mDNSlocal
void QueryRecordOpCallback(mDNS
*m
, DNSQuestion
*inQuestion
, const ResourceRecord
*inAnswer
, QC_result inAddRecord
)
522 QueryRecordOp
*const op
= (QueryRecordOp
*)inQuestion
->QuestionContext
;
523 const domainname
* domain
;
525 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
526 if ((inQuestion
== op
->q2
) && (inQuestion
->qtype
== kDNSType_SOA
))
528 DNSQuestion
* const q2
= op
->q2
;
530 if (inAnswer
->rrtype
!= kDNSType_SOA
) goto exit
;
531 QueryRecordOpStopQuestion(q2
);
533 // Restore DNSQuestion variables that were modified for the SOA query.
535 q2
->qtype
= op
->q2Type
;
536 q2
->LongLived
= op
->q2LongLived
;
537 q2
->ReturnIntermed
= op
->q2ReturnIntermed
;
538 q2
->TimeoutQuestion
= op
->q2TimeoutQuestion
;
539 q2
->AppendSearchDomains
= op
->q2AppendSearchDomains
;
541 if (inAnswer
->RecordType
!= kDNSRecordTypePacketNegative
)
543 QueryRecordOpRestartUnicastQuestion(op
, q2
, mDNSNULL
);
545 else if (q2
->AppendSearchDomains
)
547 domain
= NextSearchDomain(op
);
548 if (domain
) QueryRecordOpRestartUnicastQuestion(op
, q2
, domain
);
554 if (inAddRecord
== QC_suppressed
)
556 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEBUG
,
557 "[R%u] QueryRecordOpCallback: Suppressed question " PRI_DM_NAME
" (" PUB_S
")",
558 op
->reqID
, DM_NAME_PARAM(inQuestion
->qname
.c
), DNSTypeName(inQuestion
->qtype
));
560 resultErr
= kDNSServiceErr_NoSuchRecord
;
562 else if (inAnswer
->RecordType
== kDNSRecordTypePacketNegative
)
564 if (inQuestion
->TimeoutQuestion
&& ((GetTimeNow(m
) - inQuestion
->StopTime
) >= 0))
566 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
567 "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME
" (" PUB_S
") timing out, InterfaceID %p",
568 op
->reqID
, DM_NAME_PARAM(inQuestion
->qname
.c
), DNSTypeName(inQuestion
->qtype
),
569 inQuestion
->InterfaceID
);
570 resultErr
= kDNSServiceErr_Timeout
;
574 if (inQuestion
->AppendSearchDomains
&& (op
->searchListIndex
>= 0) && inAddRecord
&& (inAddRecord
!= QC_dnssec
))
576 domain
= NextSearchDomain(op
);
577 if (domain
|| DomainNameIsSingleLabel(op
->qname
))
579 QueryRecordOpStopQuestion(inQuestion
);
580 QueryRecordOpRestartUnicastQuestion(op
, inQuestion
, domain
);
584 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
585 if (!inAnswer
->InterfaceID
&& IsLocalDomain(inAnswer
->name
))
587 if ((RecordTypeIsAddress(inQuestion
->qtype
) &&
588 (inAnswer
->negativeRecordType
== kNegativeRecordType_NoData
)) ||
589 DomainNameIsInSearchList(&inQuestion
->qname
, mDNStrue
))
591 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
592 "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME
" (" PUB_S
") answering local with negative unicast response",
593 op
->reqID
, DM_NAME_PARAM(inQuestion
->qname
.c
), DNSTypeName(inQuestion
->qtype
));
601 resultErr
= kDNSServiceErr_NoSuchRecord
;
606 resultErr
= kDNSServiceErr_NoError
;
609 #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
610 if ((resultErr
!= kDNSServiceErr_Timeout
) && (inAddRecord
== QC_add
))
612 op
->answered
= mDNStrue
;
616 if (op
->resultHandler
) op
->resultHandler(m
, inQuestion
, inAnswer
, inAddRecord
, resultErr
, op
->resultContext
);
617 if (resultErr
== kDNSServiceErr_Timeout
) QueryRecordOpStopQuestion(inQuestion
);
619 #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
620 NotifyWebContentFilter(inAnswer
, inQuestion
->euid
);
627 mDNSlocal
void QueryRecordOpResetHandler(DNSQuestion
*inQuestion
)
629 QueryRecordOp
*const op
= (QueryRecordOp
*)inQuestion
->QuestionContext
;
631 AssignDomainName(&inQuestion
->qname
, op
->qname
);
632 if (inQuestion
->AppendSearchDomains
&& DomainNameIsSingleLabel(op
->qname
))
634 inQuestion
->InterfaceID
= mDNSInterface_LocalOnly
;
638 inQuestion
->InterfaceID
= op
->interfaceID
;
640 op
->searchListIndex
= 0;
643 mDNSlocal mStatus
QueryRecordOpStartQuestion(QueryRecordOp
*inOp
, DNSQuestion
*inQuestion
)
647 inQuestion
->QuestionContext
= inOp
;
648 err
= mDNS_StartQuery(&mDNSStorage
, inQuestion
);
651 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
652 "[R%u] ERROR: QueryRecordOpStartQuestion mDNS_StartQuery for " PRI_DM_NAME
" " PUB_S
" failed with error %d",
653 inOp
->reqID
, DM_NAME_PARAM(inQuestion
->qname
.c
), DNSTypeName(inQuestion
->qtype
), err
);
654 inQuestion
->QuestionContext
= mDNSNULL
;
659 mDNSlocal mStatus
QueryRecordOpStopQuestion(DNSQuestion
*inQuestion
)
663 err
= mDNS_StopQuery(&mDNSStorage
, inQuestion
);
664 inQuestion
->QuestionContext
= mDNSNULL
;
668 mDNSlocal mStatus
QueryRecordOpRestartUnicastQuestion(QueryRecordOp
*inOp
, DNSQuestion
*inQuestion
,
669 const domainname
*inSearchDomain
)
673 inQuestion
->InterfaceID
= inOp
->interfaceID
;
674 AssignDomainName(&inQuestion
->qname
, inOp
->qname
);
675 if (inSearchDomain
) AppendDomainName(&inQuestion
->qname
, inSearchDomain
);
676 if (SameDomainLabel(LastLabel(&inQuestion
->qname
), (const mDNSu8
*)&localdomain
))
678 inQuestion
->IsUnicastDotLocal
= mDNStrue
;
682 inQuestion
->IsUnicastDotLocal
= mDNSfalse
;
684 err
= QueryRecordOpStartQuestion(inOp
, inQuestion
);
688 mDNSlocal mStatus
InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex
, mDNSInterfaceID
*outInterfaceID
)
691 mDNSInterfaceID interfaceID
;
693 interfaceID
= mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage
, inInterfaceIndex
);
695 #if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
696 // The request is scoped to a specific interface index, but the interface is not currently in our list.
697 if ((inInterfaceIndex
!= kDNSServiceInterfaceIndexAny
) && (interfaceID
== mDNSInterface_Any
))
699 static dispatch_once_t getLoopbackIndexOnce
= 0;
700 static mDNSu32 loopbackIndex
= 0;
702 dispatch_once(&getLoopbackIndexOnce
,
704 loopbackIndex
= if_nametoindex("lo0");
707 // If it's one of the specially defined inteface index values, just return an error. Also, caller should return an
708 // error immediately if lo0 is not configured into the current active interfaces. See <rdar://problem/21967160>.
709 if ((inInterfaceIndex
== kDNSServiceInterfaceIndexLocalOnly
) ||
710 (inInterfaceIndex
== kDNSServiceInterfaceIndexUnicast
) ||
711 (inInterfaceIndex
== kDNSServiceInterfaceIndexP2P
) ||
712 (inInterfaceIndex
== kDNSServiceInterfaceIndexBLE
) ||
713 (inInterfaceIndex
== loopbackIndex
))
715 LogInfo("ERROR: bad interfaceIndex %d", inInterfaceIndex
);
716 err
= mStatus_BadParamErr
;
720 // Otherwise, use the specified interface index value and the request will be applied to that interface when it
722 interfaceID
= (mDNSInterfaceID
)(uintptr_t)inInterfaceIndex
;
723 LogInfo("Query pending for interface index %d", inInterfaceIndex
);
727 *outInterfaceID
= interfaceID
;
728 err
= mStatus_NoError
;
730 #if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
736 mDNSlocal mDNSBool
DomainNameIsSingleLabel(const domainname
*inName
)
738 const mDNSu8
*const label
= inName
->c
;
739 return (((label
[0] != 0) && (label
[1 + label
[0]] == 0)) ? mDNStrue
: mDNSfalse
);
742 mDNSlocal mDNSBool
StringEndsWithDot(const char *inString
)
748 // Loop invariant: escapeCount is the number of consecutive escape characters that immediately precede *ptr.
749 // - If escapeCount is even, then *ptr is immediately preceded by escapeCount / 2 consecutive literal backslash
750 // characters, so *ptr is not escaped.
751 // - If escapeCount is odd, then *ptr is immediately preceded by (escapeCount - 1) / 2 consecutive literal backslash
752 // characters followed by an escape character, so *ptr is escaped.
755 for (ptr
= inString
; *ptr
!= '\0'; ptr
++)
763 if ((*ptr
== '.') && (ptr
[1] == '\0'))
765 if ((escapeCount
% 2) == 0) result
= mDNStrue
;
774 mDNSlocal
const domainname
* NextSearchDomain(QueryRecordOp
*inOp
)
776 const domainname
* domain
;
778 while ((domain
= uDNS_GetNextSearchDomain(inOp
->interfaceID
, &inOp
->searchListIndex
, mDNSfalse
)) != mDNSNULL
)
780 if ((DomainNameLength(inOp
->qname
) - 1 + DomainNameLength(domain
)) <= MAX_DOMAIN_NAME
) break;
782 if (!domain
) inOp
->searchListIndex
= -1;
786 #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
787 mDNSlocal mDNSBool
DomainNameIsInSearchList(const domainname
*inName
, mDNSBool inExcludeLocal
)
789 const SearchListElem
* item
;
790 int labelCount
, domainLabelCount
;
792 labelCount
= CountLabels(inName
);
793 for (item
= SearchList
; item
; item
= item
->next
)
795 if (inExcludeLocal
&& SameDomainName(&item
->domain
, &localdomain
)) continue;
796 domainLabelCount
= CountLabels(&item
->domain
);
797 if (labelCount
>= domainLabelCount
)
799 if (SameDomainName(&item
->domain
, SkipLeadingLabels(inName
, (labelCount
- domainLabelCount
))))
809 #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
810 mDNSlocal
void NotifyWebContentFilter(const ResourceRecord
*inAnswer
, uid_t inUID
)
812 if (WCFIsServerRunning
)
814 const mDNS
*const m
= &mDNSStorage
;
816 if (WCFIsServerRunning(m
->WCF
) && inAnswer
->rdlength
!= 0)
818 struct sockaddr_storage addr
;
820 if (inAnswer
->rrtype
== kDNSType_A
|| inAnswer
->rrtype
== kDNSType_AAAA
)
822 if (inAnswer
->rrtype
== kDNSType_A
)
824 struct sockaddr_in
*const sin
= (struct sockaddr_in
*)&addr
;
826 // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
827 // sin->sin_addr.s_addr = inAnswer->rdata->u.ipv4.NotAnInteger;
828 if (!putRData(mDNSNULL
, (mDNSu8
*)&sin
->sin_addr
, (mDNSu8
*)(&sin
->sin_addr
+ sizeof(mDNSv4Addr
)), inAnswer
))
829 LogMsg("NotifyWebContentFilter: WCF AF_INET putRData failed");
832 addr
.ss_len
= sizeof (struct sockaddr_in
);
833 addr
.ss_family
= AF_INET
;
836 else if (inAnswer
->rrtype
== kDNSType_AAAA
)
838 struct sockaddr_in6
*const sin6
= (struct sockaddr_in6
*)&addr
;
840 // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
841 // sin6->sin6_addr.__u6_addr.__u6_addr32[0] = inAnswer->rdata->u.ipv6.l[0];
842 // sin6->sin6_addr.__u6_addr.__u6_addr32[1] = inAnswer->rdata->u.ipv6.l[1];
843 // sin6->sin6_addr.__u6_addr.__u6_addr32[2] = inAnswer->rdata->u.ipv6.l[2];
844 // sin6->sin6_addr.__u6_addr.__u6_addr32[3] = inAnswer->rdata->u.ipv6.l[3];
845 if (!putRData(mDNSNULL
, (mDNSu8
*)&sin6
->sin6_addr
, (mDNSu8
*)(&sin6
->sin6_addr
+ sizeof(mDNSv6Addr
)), inAnswer
))
846 LogMsg("NotifyWebContentFilter: WCF AF_INET6 putRData failed");
849 addr
.ss_len
= sizeof (struct sockaddr_in6
);
850 addr
.ss_family
= AF_INET6
;
855 char name
[MAX_ESCAPED_DOMAIN_NAME
];
856 ConvertDomainNameToCString(inAnswer
->name
, name
);
858 debugf("NotifyWebContentFilter: Name %s, uid %u, addr length %d", name
, inUID
, addr
.ss_len
);
859 if (WCFNameResolvesToAddr
)
861 WCFNameResolvesToAddr(m
->WCF
, name
, (struct sockaddr
*)&addr
, inUID
);
865 else if (inAnswer
->rrtype
== kDNSType_CNAME
)
868 char name
[MAX_ESCAPED_DOMAIN_NAME
];
869 char cname_cstr
[MAX_ESCAPED_DOMAIN_NAME
];
871 if (!putRData(mDNSNULL
, cname
.c
, (mDNSu8
*)(cname
.c
+ MAX_DOMAIN_NAME
), inAnswer
))
872 LogMsg("NotifyWebContentFilter: WCF CNAME putRData failed");
875 ConvertDomainNameToCString(inAnswer
->name
, name
);
876 ConvertDomainNameToCString(&cname
, cname_cstr
);
877 if (WCFNameResolvesToAddr
)
879 WCFNameResolvesToName(m
->WCF
, name
, cname_cstr
, inUID
);