1*472cd20dSToomas Soome /*
2*472cd20dSToomas Soome  * Copyright (c) 2018-2020 Apple Inc. All rights reserved.
3*472cd20dSToomas Soome  *
4*472cd20dSToomas Soome  * Licensed under the Apache License, Version 2.0 (the "License");
5*472cd20dSToomas Soome  * you may not use this file except in compliance with the License.
6*472cd20dSToomas Soome  * You may obtain a copy of the License at
7*472cd20dSToomas Soome  *
8*472cd20dSToomas Soome  *     http://www.apache.org/licenses/LICENSE-2.0
9*472cd20dSToomas Soome  *
10*472cd20dSToomas Soome  * Unless required by applicable law or agreed to in writing, software
11*472cd20dSToomas Soome  * distributed under the License is distributed on an "AS IS" BASIS,
12*472cd20dSToomas Soome  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*472cd20dSToomas Soome  * See the License for the specific language governing permissions and
14*472cd20dSToomas Soome  * limitations under the License.
15*472cd20dSToomas Soome  */
16*472cd20dSToomas Soome 
17*472cd20dSToomas Soome #include "ClientRequests.h"
18*472cd20dSToomas Soome 
19*472cd20dSToomas Soome #include "DNSCommon.h"
20*472cd20dSToomas Soome #include "uDNS.h"
21*472cd20dSToomas Soome 
22*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
23*472cd20dSToomas Soome #include "QuerierSupport.h"
24*472cd20dSToomas Soome #endif
25*472cd20dSToomas Soome 
26*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
27*472cd20dSToomas Soome #include "D2D.h"
28*472cd20dSToomas Soome #endif
29*472cd20dSToomas Soome 
30*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
31*472cd20dSToomas Soome #include "mDNSMacOSX.h"
32*472cd20dSToomas Soome #endif
33*472cd20dSToomas Soome 
34*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
35*472cd20dSToomas Soome #include <dispatch/dispatch.h>
36*472cd20dSToomas Soome #include <net/if.h>
37*472cd20dSToomas Soome #endif
38*472cd20dSToomas Soome 
39*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
40*472cd20dSToomas Soome #include <WebFilterDNS/WebFilterDNS.h>
41*472cd20dSToomas Soome 
42*472cd20dSToomas Soome int WCFIsServerRunning(WCFConnection *conn) __attribute__((weak_import));
43*472cd20dSToomas Soome int WCFNameResolvesToAddr(WCFConnection *conn, char* domainName, struct sockaddr* address, uid_t userid) __attribute__((weak_import));
44*472cd20dSToomas Soome int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid_t userid) __attribute__((weak_import));
45*472cd20dSToomas Soome #endif
46*472cd20dSToomas Soome 
47*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
48*472cd20dSToomas Soome #include "dnssec_v2.h"
49*472cd20dSToomas Soome #endif
50*472cd20dSToomas Soome 
51*472cd20dSToomas Soome #define RecordTypeIsAddress(TYPE)   (((TYPE) == kDNSType_A) || ((TYPE) == kDNSType_AAAA))
52*472cd20dSToomas Soome 
53*472cd20dSToomas Soome extern mDNS mDNSStorage;
54*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
55*472cd20dSToomas Soome extern domainname ActiveDirectoryPrimaryDomain;
56*472cd20dSToomas Soome #endif
57*472cd20dSToomas Soome 
58*472cd20dSToomas Soome // Normally we append search domains only for queries with a single label that are not fully qualified. This can be
59*472cd20dSToomas Soome // overridden to apply search domains for queries (that are not fully qualified) with any number of labels e.g., moon,
60*472cd20dSToomas Soome // moon.cs, moon.cs.be, etc. - Mohan
61*472cd20dSToomas Soome mDNSBool AlwaysAppendSearchDomains = mDNSfalse;
62*472cd20dSToomas Soome 
63*472cd20dSToomas Soome // Control enabling optimistic DNS - Phil
64*472cd20dSToomas Soome mDNSBool EnableAllowExpired = mDNStrue;
65*472cd20dSToomas Soome 
66*472cd20dSToomas Soome 
67*472cd20dSToomas Soome typedef struct
68*472cd20dSToomas Soome {
69*472cd20dSToomas Soome     mDNSu32                 requestID;
70*472cd20dSToomas Soome     const domainname *      qname;
71*472cd20dSToomas Soome     mDNSu16                 qtype;
72*472cd20dSToomas Soome     mDNSu16                 qclass;
73*472cd20dSToomas Soome     mDNSInterfaceID         interfaceID;
74*472cd20dSToomas Soome     mDNSs32                 serviceID;
75*472cd20dSToomas Soome     mDNSu32                 flags;
76*472cd20dSToomas Soome     mDNSBool                appendSearchDomains;
77*472cd20dSToomas Soome     mDNSs32                 effectivePID;
78*472cd20dSToomas Soome     const mDNSu8 *          effectiveUUID;
79*472cd20dSToomas Soome     mDNSu32                 peerUID;
80*472cd20dSToomas Soome     mDNSBool                isInAppBrowserRequest;
81*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
82*472cd20dSToomas Soome     const mDNSu8 *          resolverUUID;
83*472cd20dSToomas Soome 	mdns_dns_service_id_t	customID;
84*472cd20dSToomas Soome     mDNSBool                needEncryption;
85*472cd20dSToomas Soome #endif
86*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
87*472cd20dSToomas Soome     const audit_token_t *   peerAuditToken;
88*472cd20dSToomas Soome     const audit_token_t *   delegatorAuditToken;
89*472cd20dSToomas Soome #endif
90*472cd20dSToomas Soome 
91*472cd20dSToomas Soome }   QueryRecordOpParams;
92*472cd20dSToomas Soome 
QueryRecordOpParamsInit(QueryRecordOpParams * inParams)93*472cd20dSToomas Soome mDNSlocal void QueryRecordOpParamsInit(QueryRecordOpParams *inParams)
94*472cd20dSToomas Soome {
95*472cd20dSToomas Soome 	mDNSPlatformMemZero(inParams, (mDNSu32)sizeof(*inParams));
96*472cd20dSToomas Soome     inParams->serviceID = -1;
97*472cd20dSToomas Soome }
98*472cd20dSToomas Soome 
99*472cd20dSToomas Soome mDNSlocal mStatus QueryRecordOpCreate(QueryRecordOp **outOp);
100*472cd20dSToomas Soome mDNSlocal void QueryRecordOpFree(QueryRecordOp *operation);
101*472cd20dSToomas Soome mDNSlocal mStatus QueryRecordOpStart(QueryRecordOp *inOp, const QueryRecordOpParams *inParams,
102*472cd20dSToomas Soome     QueryRecordResultHandler inResultHandler, void *inResultContext);
103*472cd20dSToomas Soome mDNSlocal void QueryRecordOpStop(QueryRecordOp *op);
104*472cd20dSToomas Soome mDNSlocal mDNSBool QueryRecordOpIsMulticast(const QueryRecordOp *op);
105*472cd20dSToomas Soome mDNSlocal void QueryRecordOpCallback(mDNS *m, DNSQuestion *inQuestion, const ResourceRecord *inAnswer,
106*472cd20dSToomas Soome     QC_result inAddRecord);
107*472cd20dSToomas Soome mDNSlocal void QueryRecordOpResetHandler(DNSQuestion *inQuestion);
108*472cd20dSToomas Soome mDNSlocal mStatus QueryRecordOpStartQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion);
109*472cd20dSToomas Soome mDNSlocal mStatus QueryRecordOpStopQuestion(DNSQuestion *inQuestion);
110*472cd20dSToomas Soome mDNSlocal mStatus QueryRecordOpRestartUnicastQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion,
111*472cd20dSToomas Soome     const domainname *inSearchDomain);
112*472cd20dSToomas Soome mDNSlocal mStatus InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex, mDNSInterfaceID *outInterfaceID);
113*472cd20dSToomas Soome mDNSlocal mDNSBool DomainNameIsSingleLabel(const domainname *inName);
114*472cd20dSToomas Soome mDNSlocal mDNSBool StringEndsWithDot(const char *inString);
115*472cd20dSToomas Soome mDNSlocal const domainname * NextSearchDomain(QueryRecordOp *inOp);
116*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
117*472cd20dSToomas Soome mDNSlocal mDNSBool DomainNameIsInSearchList(const domainname *domain, mDNSBool inExcludeLocal);
118*472cd20dSToomas Soome #endif
119*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
120*472cd20dSToomas Soome mDNSlocal void NotifyWebContentFilter(const ResourceRecord *inAnswer, uid_t inUID);
121*472cd20dSToomas Soome #endif
122*472cd20dSToomas Soome 
GetAddrInfoClientRequestParamsInit(GetAddrInfoClientRequestParams * inParams)123*472cd20dSToomas Soome mDNSexport void GetAddrInfoClientRequestParamsInit(GetAddrInfoClientRequestParams *inParams)
124*472cd20dSToomas Soome {
125*472cd20dSToomas Soome 	mDNSPlatformMemZero(inParams, (mDNSu32)sizeof(*inParams));
126*472cd20dSToomas Soome }
127*472cd20dSToomas Soome 
GetAddrInfoClientRequestStart(GetAddrInfoClientRequest * inRequest,const GetAddrInfoClientRequestParams * inParams,QueryRecordResultHandler inResultHandler,void * inResultContext)128*472cd20dSToomas Soome mDNSexport mStatus GetAddrInfoClientRequestStart(GetAddrInfoClientRequest *inRequest,
129*472cd20dSToomas Soome     const GetAddrInfoClientRequestParams *inParams, QueryRecordResultHandler inResultHandler, void *inResultContext)
130*472cd20dSToomas Soome {
131*472cd20dSToomas Soome     mStatus             err;
132*472cd20dSToomas Soome     domainname          hostname;
133*472cd20dSToomas Soome     mDNSBool            appendSearchDomains;
134*472cd20dSToomas Soome     mDNSInterfaceID     interfaceID;
135*472cd20dSToomas Soome     DNSServiceFlags     flags;
136*472cd20dSToomas Soome     mDNSs32             serviceID;
137*472cd20dSToomas Soome     QueryRecordOpParams opParams;
138*472cd20dSToomas Soome 
139*472cd20dSToomas Soome     if (!MakeDomainNameFromDNSNameString(&hostname, inParams->hostnameStr))
140*472cd20dSToomas Soome     {
141*472cd20dSToomas Soome         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
142*472cd20dSToomas Soome                "[R%u] ERROR: bad hostname '" PRI_S "'", inParams->requestID, inParams->hostnameStr);
143*472cd20dSToomas Soome         err = mStatus_BadParamErr;
144*472cd20dSToomas Soome         goto exit;
145*472cd20dSToomas Soome     }
146*472cd20dSToomas Soome 
147*472cd20dSToomas Soome     if (inParams->protocols & ~(kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6))
148*472cd20dSToomas Soome     {
149*472cd20dSToomas Soome         err = mStatus_BadParamErr;
150*472cd20dSToomas Soome         goto exit;
151*472cd20dSToomas Soome     }
152*472cd20dSToomas Soome 
153*472cd20dSToomas Soome     flags = inParams->flags;
154*472cd20dSToomas Soome     if (inParams->protocols == 0)
155*472cd20dSToomas Soome     {
156*472cd20dSToomas Soome         flags |= kDNSServiceFlagsSuppressUnusable;
157*472cd20dSToomas Soome         inRequest->protocols = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6;
158*472cd20dSToomas Soome     }
159*472cd20dSToomas Soome     else
160*472cd20dSToomas Soome     {
161*472cd20dSToomas Soome         inRequest->protocols = inParams->protocols;
162*472cd20dSToomas Soome     }
163*472cd20dSToomas Soome 
164*472cd20dSToomas Soome     if (flags & kDNSServiceFlagsServiceIndex)
165*472cd20dSToomas Soome     {
166*472cd20dSToomas Soome         // NOTE: kDNSServiceFlagsServiceIndex flag can only be set for DNSServiceGetAddrInfo()
167*472cd20dSToomas Soome         LogInfo("GetAddrInfoClientRequestStart: kDNSServiceFlagsServiceIndex is SET by the client");
168*472cd20dSToomas Soome 
169*472cd20dSToomas Soome         // If kDNSServiceFlagsServiceIndex is SET, interpret the interfaceID as the serviceId and set the interfaceID to 0.
170*472cd20dSToomas Soome         serviceID   = (mDNSs32)inParams->interfaceIndex;
171*472cd20dSToomas Soome         interfaceID = mDNSNULL;
172*472cd20dSToomas Soome     }
173*472cd20dSToomas Soome     else
174*472cd20dSToomas Soome     {
175*472cd20dSToomas Soome         serviceID = -1;
176*472cd20dSToomas Soome         err = InterfaceIndexToInterfaceID(inParams->interfaceIndex, &interfaceID);
177*472cd20dSToomas Soome         if (err) goto exit;
178*472cd20dSToomas Soome     }
179*472cd20dSToomas Soome     inRequest->interfaceID = interfaceID;
180*472cd20dSToomas Soome 
181*472cd20dSToomas Soome     if (!StringEndsWithDot(inParams->hostnameStr) && (AlwaysAppendSearchDomains || DomainNameIsSingleLabel(&hostname)))
182*472cd20dSToomas Soome     {
183*472cd20dSToomas Soome         appendSearchDomains = mDNStrue;
184*472cd20dSToomas Soome     }
185*472cd20dSToomas Soome     else
186*472cd20dSToomas Soome     {
187*472cd20dSToomas Soome         appendSearchDomains = mDNSfalse;
188*472cd20dSToomas Soome     }
189*472cd20dSToomas Soome     QueryRecordOpParamsInit(&opParams);
190*472cd20dSToomas Soome     opParams.requestID              = inParams->requestID;
191*472cd20dSToomas Soome     opParams.qname                  = &hostname;
192*472cd20dSToomas Soome     opParams.qclass                 = kDNSClass_IN;
193*472cd20dSToomas Soome     opParams.interfaceID            = inRequest->interfaceID;
194*472cd20dSToomas Soome     opParams.serviceID              = serviceID;
195*472cd20dSToomas Soome     opParams.flags                  = flags;
196*472cd20dSToomas Soome     opParams.appendSearchDomains    = appendSearchDomains;
197*472cd20dSToomas Soome     opParams.effectivePID           = inParams->effectivePID;
198*472cd20dSToomas Soome     opParams.effectiveUUID          = inParams->effectiveUUID;
199*472cd20dSToomas Soome     opParams.peerUID                = inParams->peerUID;
200*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
201*472cd20dSToomas Soome     opParams.resolverUUID           = inParams->resolverUUID;
202*472cd20dSToomas Soome     opParams.customID               = inParams->customID;
203*472cd20dSToomas Soome     opParams.needEncryption         = inParams->needEncryption;
204*472cd20dSToomas Soome #endif
205*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
206*472cd20dSToomas Soome     opParams.peerAuditToken         = inParams->peerAuditToken;
207*472cd20dSToomas Soome     opParams.delegatorAuditToken    = inParams->delegatorAuditToken;
208*472cd20dSToomas Soome     opParams.isInAppBrowserRequest  = inParams->isInAppBrowserRequest;
209*472cd20dSToomas Soome #endif
210*472cd20dSToomas Soome     if (inRequest->protocols & kDNSServiceProtocol_IPv6)
211*472cd20dSToomas Soome     {
212*472cd20dSToomas Soome         err = QueryRecordOpCreate(&inRequest->op6);
213*472cd20dSToomas Soome         if (err) goto exit;
214*472cd20dSToomas Soome 
215*472cd20dSToomas Soome         opParams.qtype = kDNSType_AAAA;
216*472cd20dSToomas Soome         err = QueryRecordOpStart(inRequest->op6, &opParams, inResultHandler, inResultContext);
217*472cd20dSToomas Soome         if (err) goto exit;
218*472cd20dSToomas Soome     }
219*472cd20dSToomas Soome     if (inRequest->protocols & kDNSServiceProtocol_IPv4)
220*472cd20dSToomas Soome     {
221*472cd20dSToomas Soome         err = QueryRecordOpCreate(&inRequest->op4);
222*472cd20dSToomas Soome         if (err) goto exit;
223*472cd20dSToomas Soome 
224*472cd20dSToomas Soome         opParams.qtype = kDNSType_A;
225*472cd20dSToomas Soome         err = QueryRecordOpStart(inRequest->op4, &opParams, inResultHandler, inResultContext);
226*472cd20dSToomas Soome         if (err) goto exit;
227*472cd20dSToomas Soome     }
228*472cd20dSToomas Soome     err = mStatus_NoError;
229*472cd20dSToomas Soome 
230*472cd20dSToomas Soome exit:
231*472cd20dSToomas Soome     if (err) GetAddrInfoClientRequestStop(inRequest);
232*472cd20dSToomas Soome     return err;
233*472cd20dSToomas Soome }
234*472cd20dSToomas Soome 
GetAddrInfoClientRequestStop(GetAddrInfoClientRequest * inRequest)235*472cd20dSToomas Soome mDNSexport void GetAddrInfoClientRequestStop(GetAddrInfoClientRequest *inRequest)
236*472cd20dSToomas Soome {
237*472cd20dSToomas Soome     if (inRequest->op4) QueryRecordOpStop(inRequest->op4);
238*472cd20dSToomas Soome     if (inRequest->op6) QueryRecordOpStop(inRequest->op6);
239*472cd20dSToomas Soome 
240*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
241*472cd20dSToomas Soome     {
242*472cd20dSToomas Soome         const QueryRecordOp * const     op4 = inRequest->op4;
243*472cd20dSToomas Soome         const QueryRecordOp * const     op6 = inRequest->op6;
244*472cd20dSToomas Soome         const DNSQuestion *             q4  = mDNSNULL;
245*472cd20dSToomas Soome         const DNSQuestion *             q6  = mDNSNULL;
246*472cd20dSToomas Soome 
247*472cd20dSToomas Soome         if (op4)
248*472cd20dSToomas Soome         {
249*472cd20dSToomas Soome             if (op4->answered)
250*472cd20dSToomas Soome             {
251*472cd20dSToomas Soome                 // If we have a v4 answer and if we timed out prematurely before, provide a trigger to the upper layer so
252*472cd20dSToomas Soome                 // that it can retry questions if needed. - Mohan
253*472cd20dSToomas Soome                 q4 = &op4->q;
254*472cd20dSToomas Soome             }
255*472cd20dSToomas Soome             else if (op4->q.TimeoutQuestion)
256*472cd20dSToomas Soome             {
257*472cd20dSToomas Soome                 // If we are not delivering answers, we may be timing out prematurely. Note down the current state so that
258*472cd20dSToomas Soome                 // we know to retry when we see a valid response again. - Mohan
259*472cd20dSToomas Soome                 mDNSPlatformUpdateDNSStatus(&op4->q);
260*472cd20dSToomas Soome             }
261*472cd20dSToomas Soome         }
262*472cd20dSToomas Soome         if (op6)
263*472cd20dSToomas Soome         {
264*472cd20dSToomas Soome             if (op6->answered)
265*472cd20dSToomas Soome             {
266*472cd20dSToomas Soome                 q6 = &op6->q;
267*472cd20dSToomas Soome             }
268*472cd20dSToomas Soome             else if (op6->q.TimeoutQuestion)
269*472cd20dSToomas Soome             {
270*472cd20dSToomas Soome                 mDNSPlatformUpdateDNSStatus(&op6->q);
271*472cd20dSToomas Soome             }
272*472cd20dSToomas Soome         }
273*472cd20dSToomas Soome         mDNSPlatformTriggerDNSRetry(q4, q6);
274*472cd20dSToomas Soome     }
275*472cd20dSToomas Soome #endif
276*472cd20dSToomas Soome 
277*472cd20dSToomas Soome     if (inRequest->op4)
278*472cd20dSToomas Soome     {
279*472cd20dSToomas Soome         QueryRecordOpFree(inRequest->op4);
280*472cd20dSToomas Soome         inRequest->op4 = mDNSNULL;
281*472cd20dSToomas Soome     }
282*472cd20dSToomas Soome     if (inRequest->op6)
283*472cd20dSToomas Soome     {
284*472cd20dSToomas Soome         QueryRecordOpFree(inRequest->op6);
285*472cd20dSToomas Soome         inRequest->op6 = mDNSNULL;
286*472cd20dSToomas Soome     }
287*472cd20dSToomas Soome }
288*472cd20dSToomas Soome 
GetAddrInfoClientRequestGetQName(const GetAddrInfoClientRequest * inRequest)289*472cd20dSToomas Soome mDNSexport const domainname * GetAddrInfoClientRequestGetQName(const GetAddrInfoClientRequest *inRequest)
290*472cd20dSToomas Soome {
291*472cd20dSToomas Soome     if (inRequest->op4) return &inRequest->op4->q.qname;
292*472cd20dSToomas Soome     if (inRequest->op6) return &inRequest->op6->q.qname;
293*472cd20dSToomas Soome     return (const domainname *)"";
294*472cd20dSToomas Soome }
295*472cd20dSToomas Soome 
GetAddrInfoClientRequestIsMulticast(const GetAddrInfoClientRequest * inRequest)296*472cd20dSToomas Soome mDNSexport mDNSBool GetAddrInfoClientRequestIsMulticast(const GetAddrInfoClientRequest *inRequest)
297*472cd20dSToomas Soome {
298*472cd20dSToomas Soome     if ((inRequest->op4 && QueryRecordOpIsMulticast(inRequest->op4)) ||
299*472cd20dSToomas Soome         (inRequest->op6 && QueryRecordOpIsMulticast(inRequest->op6)))
300*472cd20dSToomas Soome     {
301*472cd20dSToomas Soome         return mDNStrue;
302*472cd20dSToomas Soome     }
303*472cd20dSToomas Soome     return mDNSfalse;
304*472cd20dSToomas Soome }
305*472cd20dSToomas Soome 
QueryRecordClientRequestParamsInit(QueryRecordClientRequestParams * inParams)306*472cd20dSToomas Soome mDNSexport void QueryRecordClientRequestParamsInit(QueryRecordClientRequestParams *inParams)
307*472cd20dSToomas Soome {
308*472cd20dSToomas Soome 	mDNSPlatformMemZero(inParams, (mDNSu32)sizeof(*inParams));
309*472cd20dSToomas Soome }
310*472cd20dSToomas Soome 
QueryRecordClientRequestStart(QueryRecordClientRequest * inRequest,const QueryRecordClientRequestParams * inParams,QueryRecordResultHandler inResultHandler,void * inResultContext)311*472cd20dSToomas Soome mDNSexport mStatus QueryRecordClientRequestStart(QueryRecordClientRequest *inRequest,
312*472cd20dSToomas Soome     const QueryRecordClientRequestParams *inParams, QueryRecordResultHandler inResultHandler, void *inResultContext)
313*472cd20dSToomas Soome {
314*472cd20dSToomas Soome     mStatus             err;
315*472cd20dSToomas Soome     domainname          qname;
316*472cd20dSToomas Soome     mDNSInterfaceID     interfaceID;
317*472cd20dSToomas Soome     mDNSBool            appendSearchDomains;
318*472cd20dSToomas Soome     QueryRecordOpParams opParams;
319*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
320*472cd20dSToomas Soome     dnssec_context_t *  dnssecContext = mDNSNULL;
321*472cd20dSToomas Soome #endif
322*472cd20dSToomas Soome 
323*472cd20dSToomas Soome     err = InterfaceIndexToInterfaceID(inParams->interfaceIndex, &interfaceID);
324*472cd20dSToomas Soome     if (err) goto exit;
325*472cd20dSToomas Soome 
326*472cd20dSToomas Soome     if (!MakeDomainNameFromDNSNameString(&qname, inParams->qnameStr))
327*472cd20dSToomas Soome     {
328*472cd20dSToomas Soome         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
329*472cd20dSToomas Soome                "[R%u] ERROR: bad domain name '" PRI_S "'", inParams->requestID, inParams->qnameStr);
330*472cd20dSToomas Soome         err = mStatus_BadParamErr;
331*472cd20dSToomas Soome         goto exit;
332*472cd20dSToomas Soome     }
333*472cd20dSToomas Soome 
334*472cd20dSToomas Soome     if (RecordTypeIsAddress(inParams->qtype) && !StringEndsWithDot(inParams->qnameStr) &&
335*472cd20dSToomas Soome         (AlwaysAppendSearchDomains || DomainNameIsSingleLabel(&qname)))
336*472cd20dSToomas Soome     {
337*472cd20dSToomas Soome         appendSearchDomains = mDNStrue;
338*472cd20dSToomas Soome     }
339*472cd20dSToomas Soome     else
340*472cd20dSToomas Soome     {
341*472cd20dSToomas Soome         appendSearchDomains = mDNSfalse;
342*472cd20dSToomas Soome     }
343*472cd20dSToomas Soome     QueryRecordOpParamsInit(&opParams);
344*472cd20dSToomas Soome     opParams.requestID              = inParams->requestID;
345*472cd20dSToomas Soome     opParams.qname                  = &qname;
346*472cd20dSToomas Soome     opParams.qtype                  = inParams->qtype;
347*472cd20dSToomas Soome     opParams.qclass                 = inParams->qclass;
348*472cd20dSToomas Soome     opParams.interfaceID            = interfaceID;
349*472cd20dSToomas Soome     opParams.appendSearchDomains    = appendSearchDomains;
350*472cd20dSToomas Soome     opParams.effectivePID           = inParams->effectivePID;
351*472cd20dSToomas Soome     opParams.effectiveUUID          = inParams->effectiveUUID;
352*472cd20dSToomas Soome     opParams.peerUID                = inParams->peerUID;
353*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
354*472cd20dSToomas Soome     opParams.resolverUUID           = inParams->resolverUUID;
355*472cd20dSToomas Soome     opParams.customID               = inParams->customID;
356*472cd20dSToomas Soome     opParams.needEncryption         = inParams->needEncryption;
357*472cd20dSToomas Soome #endif
358*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
359*472cd20dSToomas Soome     opParams.peerAuditToken         = inParams->peerAuditToken;
360*472cd20dSToomas Soome     opParams.delegatorAuditToken    = inParams->delegatorAuditToken;
361*472cd20dSToomas Soome     opParams.isInAppBrowserRequest  = inParams->isInAppBrowserRequest;
362*472cd20dSToomas Soome #endif
363*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
364*472cd20dSToomas Soome     // Query ends with ".local." and query for RRSIG or ANY type cannot be validated by DNSSEC even if the user sets the
365*472cd20dSToomas Soome     // kDNSServiceFlagsEnableDNSSEC flag.
366*472cd20dSToomas Soome     if (FLAGS_CONTAIN_DNSOK_BIT(inParams->flags) && is_eligible_for_dnssec(&qname, inParams->qtype))
367*472cd20dSToomas Soome     {
368*472cd20dSToomas Soome         opParams.flags = inParams->flags | kDNSServiceFlagsReturnIntermediates; // to handle CNAME reference
369*472cd20dSToomas Soome         err = create_dnssec_context_t(inRequest, inParams->requestID, &qname, inParams->qtype, inParams->qclass,
370*472cd20dSToomas Soome             interfaceID, -1, inParams->flags, appendSearchDomains, inParams->effectivePID, inParams->effectiveUUID,
371*472cd20dSToomas Soome             inParams->peerUID,
372*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
373*472cd20dSToomas Soome             inParams->peerAuditToken, inParams->delegatorAuditToken,
374*472cd20dSToomas Soome #endif
375*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
376*472cd20dSToomas Soome             mDNSNULL, inParams->needEncryption, inParams->customID,
377*472cd20dSToomas Soome #endif
378*472cd20dSToomas Soome             inResultHandler, inResultContext, mDNSNULL, &dnssecContext);
379*472cd20dSToomas Soome         require_action(err == mStatus_NoError, exit, log_debug("create_dnssec_context_t failed; error_description='%s'",
380*472cd20dSToomas Soome             mStatusDescription(err)));
381*472cd20dSToomas Soome 
382*472cd20dSToomas Soome         err = QueryRecordOpStart(&inRequest->op, &opParams, query_record_result_reply_with_dnssec, dnssecContext);
383*472cd20dSToomas Soome     } else
384*472cd20dSToomas Soome #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
385*472cd20dSToomas Soome     {
386*472cd20dSToomas Soome         opParams.flags = inParams->flags;
387*472cd20dSToomas Soome         err = QueryRecordOpStart(&inRequest->op, &opParams, inResultHandler, inResultContext);
388*472cd20dSToomas Soome     }
389*472cd20dSToomas Soome 
390*472cd20dSToomas Soome exit:
391*472cd20dSToomas Soome     if (err) QueryRecordClientRequestStop(inRequest);
392*472cd20dSToomas Soome     return err;
393*472cd20dSToomas Soome }
394*472cd20dSToomas Soome 
QueryRecordClientRequestStop(QueryRecordClientRequest * inRequest)395*472cd20dSToomas Soome mDNSexport void QueryRecordClientRequestStop(QueryRecordClientRequest *inRequest)
396*472cd20dSToomas Soome {
397*472cd20dSToomas Soome     QueryRecordOpStop(&inRequest->op);
398*472cd20dSToomas Soome 
399*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
400*472cd20dSToomas Soome     stop_dnssec_if_enable_dnssec(inRequest);
401*472cd20dSToomas Soome #endif
402*472cd20dSToomas Soome 
403*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
404*472cd20dSToomas Soome     if (inRequest->op.answered)
405*472cd20dSToomas Soome     {
406*472cd20dSToomas Soome         DNSQuestion *v4q, *v6q;
407*472cd20dSToomas Soome         // If we are receiving positive answers, provide the hint to the upper layer. - Mohan
408*472cd20dSToomas Soome         v4q = (inRequest->op.q.qtype == kDNSType_A)    ? &inRequest->op.q : mDNSNULL;
409*472cd20dSToomas Soome         v6q = (inRequest->op.q.qtype == kDNSType_AAAA) ? &inRequest->op.q : mDNSNULL;
410*472cd20dSToomas Soome         mDNSPlatformTriggerDNSRetry(v4q, v6q);
411*472cd20dSToomas Soome     }
412*472cd20dSToomas Soome #endif
413*472cd20dSToomas Soome }
414*472cd20dSToomas Soome 
QueryRecordClientRequestGetQName(const QueryRecordClientRequest * inRequest)415*472cd20dSToomas Soome mDNSexport const domainname * QueryRecordClientRequestGetQName(const QueryRecordClientRequest *inRequest)
416*472cd20dSToomas Soome {
417*472cd20dSToomas Soome     return &inRequest->op.q.qname;
418*472cd20dSToomas Soome }
419*472cd20dSToomas Soome 
QueryRecordClientRequestGetType(const QueryRecordClientRequest * inRequest)420*472cd20dSToomas Soome mDNSexport mDNSu16 QueryRecordClientRequestGetType(const QueryRecordClientRequest *inRequest)
421*472cd20dSToomas Soome {
422*472cd20dSToomas Soome     return inRequest->op.q.qtype;
423*472cd20dSToomas Soome }
424*472cd20dSToomas Soome 
QueryRecordClientRequestIsMulticast(QueryRecordClientRequest * inRequest)425*472cd20dSToomas Soome mDNSexport mDNSBool QueryRecordClientRequestIsMulticast(QueryRecordClientRequest *inRequest)
426*472cd20dSToomas Soome {
427*472cd20dSToomas Soome     return (QueryRecordOpIsMulticast(&inRequest->op) ? mDNStrue : mDNSfalse);
428*472cd20dSToomas Soome }
429*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
QueryRecordOpStartForClientRequest(QueryRecordOp * inOp,mDNSu32 inReqID,const domainname * inQName,mDNSu16 inQType,mDNSu16 inQClass,mDNSInterfaceID inInterfaceID,mDNSs32 inServiceID,mDNSu32 inFlags,mDNSBool inAppendSearchDomains,mDNSs32 inPID,const mDNSu8 inUUID[UUID_SIZE],mDNSu32 inUID,const audit_token_t * inPeerAuditTokenPtr,const audit_token_t * inDelegateAuditTokenPtr,const mDNSu8 inResolverUUID[UUID_SIZE],mDNSBool inNeedEncryption,const mdns_dns_service_id_t inCustomID,QueryRecordResultHandler inResultHandler,void * inResultContext)430*472cd20dSToomas Soome mDNSexport mStatus QueryRecordOpStartForClientRequest(
431*472cd20dSToomas Soome     QueryRecordOp *             inOp,
432*472cd20dSToomas Soome     mDNSu32                     inReqID,
433*472cd20dSToomas Soome     const domainname *          inQName,
434*472cd20dSToomas Soome     mDNSu16                     inQType,
435*472cd20dSToomas Soome     mDNSu16                     inQClass,
436*472cd20dSToomas Soome     mDNSInterfaceID             inInterfaceID,
437*472cd20dSToomas Soome     mDNSs32                     inServiceID,
438*472cd20dSToomas Soome     mDNSu32                     inFlags,
439*472cd20dSToomas Soome     mDNSBool                    inAppendSearchDomains,
440*472cd20dSToomas Soome     mDNSs32                     inPID,
441*472cd20dSToomas Soome     const mDNSu8                inUUID[UUID_SIZE],
442*472cd20dSToomas Soome     mDNSu32                     inUID,
443*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
444*472cd20dSToomas Soome     const audit_token_t *       inPeerAuditTokenPtr,
445*472cd20dSToomas Soome     const audit_token_t *       inDelegateAuditTokenPtr,
446*472cd20dSToomas Soome #endif
447*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
448*472cd20dSToomas Soome     const mDNSu8                inResolverUUID[UUID_SIZE],
449*472cd20dSToomas Soome     mDNSBool                    inNeedEncryption,
450*472cd20dSToomas Soome     const mdns_dns_service_id_t inCustomID,
451*472cd20dSToomas Soome #endif
452*472cd20dSToomas Soome     QueryRecordResultHandler    inResultHandler,
453*472cd20dSToomas Soome     void *                      inResultContext) {
454*472cd20dSToomas Soome     QueryRecordOpParams opParams;
455*472cd20dSToomas Soome     QueryRecordOpParamsInit(&opParams);
456*472cd20dSToomas Soome     opParams.requestID           = inReqID;
457*472cd20dSToomas Soome     opParams.qname               = inQName;
458*472cd20dSToomas Soome     opParams.qtype               = inQType;
459*472cd20dSToomas Soome     opParams.qclass              = inQClass;
460*472cd20dSToomas Soome     opParams.interfaceID         = inInterfaceID;
461*472cd20dSToomas Soome     opParams.serviceID           = inServiceID;
462*472cd20dSToomas Soome     opParams.flags               = inFlags;
463*472cd20dSToomas Soome     opParams.appendSearchDomains = inAppendSearchDomains;
464*472cd20dSToomas Soome     opParams.effectivePID        = inPID;
465*472cd20dSToomas Soome     opParams.effectiveUUID       = inUUID;
466*472cd20dSToomas Soome     opParams.peerUID             = inUID;
467*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
468*472cd20dSToomas Soome     opParams.resolverUUID        = inResolverUUID;
469*472cd20dSToomas Soome     opParams.customID            = inCustomID;
470*472cd20dSToomas Soome     opParams.needEncryption      = inNeedEncryption;
471*472cd20dSToomas Soome #endif
472*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
473*472cd20dSToomas Soome     opParams.peerAuditToken      = inPeerAuditTokenPtr;
474*472cd20dSToomas Soome     opParams.delegatorAuditToken = inDelegateAuditTokenPtr;
475*472cd20dSToomas Soome #endif
476*472cd20dSToomas Soome     return QueryRecordOpStart(inOp, &opParams, inResultHandler, inResultContext);
477*472cd20dSToomas Soome }
478*472cd20dSToomas Soome 
QueryRecordOpStopForClientRequest(QueryRecordOp * op)479*472cd20dSToomas Soome mDNSexport void QueryRecordOpStopForClientRequest(QueryRecordOp *op) {
480*472cd20dSToomas Soome     QueryRecordOpStop(op);
481*472cd20dSToomas Soome }
482*472cd20dSToomas Soome 
483*472cd20dSToomas Soome #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
484*472cd20dSToomas Soome 
QueryRecordOpCreate(QueryRecordOp ** outOp)485*472cd20dSToomas Soome mDNSlocal mStatus QueryRecordOpCreate(QueryRecordOp **outOp)
486*472cd20dSToomas Soome {
487*472cd20dSToomas Soome     mStatus err;
488*472cd20dSToomas Soome     QueryRecordOp *op;
489*472cd20dSToomas Soome 
490*472cd20dSToomas Soome     op = (QueryRecordOp *) mDNSPlatformMemAllocateClear(sizeof(*op));
491*472cd20dSToomas Soome     if (!op)
492*472cd20dSToomas Soome     {
493*472cd20dSToomas Soome         err = mStatus_NoMemoryErr;
494*472cd20dSToomas Soome         goto exit;
495*472cd20dSToomas Soome     }
496*472cd20dSToomas Soome     *outOp = op;
497*472cd20dSToomas Soome     err = mStatus_NoError;
498*472cd20dSToomas Soome 
499*472cd20dSToomas Soome exit:
500*472cd20dSToomas Soome     return err;
501*472cd20dSToomas Soome }
502*472cd20dSToomas Soome 
QueryRecordOpFree(QueryRecordOp * operation)503*472cd20dSToomas Soome mDNSlocal void QueryRecordOpFree(QueryRecordOp *operation)
504*472cd20dSToomas Soome {
505*472cd20dSToomas Soome     mDNSPlatformMemFree(operation);
506*472cd20dSToomas Soome }
507*472cd20dSToomas Soome 
508*472cd20dSToomas Soome #define VALID_MSAD_SRV_TRANSPORT(T) \
509*472cd20dSToomas Soome     (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp"))
510*472cd20dSToomas Soome #define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname)))
511*472cd20dSToomas Soome 
QueryRecordOpStart(QueryRecordOp * inOp,const QueryRecordOpParams * inParams,QueryRecordResultHandler inResultHandler,void * inResultContext)512*472cd20dSToomas Soome mDNSlocal mStatus QueryRecordOpStart(QueryRecordOp *inOp, const QueryRecordOpParams *inParams,
513*472cd20dSToomas Soome     QueryRecordResultHandler inResultHandler, void *inResultContext)
514*472cd20dSToomas Soome {
515*472cd20dSToomas Soome     mStatus                 err;
516*472cd20dSToomas Soome     DNSQuestion * const     q = &inOp->q;
517*472cd20dSToomas Soome     mDNSu32                 len;
518*472cd20dSToomas Soome 
519*472cd20dSToomas Soome     // Save the original qname.
520*472cd20dSToomas Soome 
521*472cd20dSToomas Soome     len = DomainNameLength(inParams->qname);
522*472cd20dSToomas Soome     inOp->qname = (domainname *) mDNSPlatformMemAllocate(len);
523*472cd20dSToomas Soome     if (!inOp->qname)
524*472cd20dSToomas Soome     {
525*472cd20dSToomas Soome         err = mStatus_NoMemoryErr;
526*472cd20dSToomas Soome         goto exit;
527*472cd20dSToomas Soome     }
528*472cd20dSToomas Soome     mDNSPlatformMemCopy(inOp->qname, inParams->qname, len);
529*472cd20dSToomas Soome 
530*472cd20dSToomas Soome     inOp->interfaceID   = inParams->interfaceID;
531*472cd20dSToomas Soome     inOp->reqID         = inParams->requestID;
532*472cd20dSToomas Soome     inOp->resultHandler = inResultHandler;
533*472cd20dSToomas Soome     inOp->resultContext = inResultContext;
534*472cd20dSToomas Soome 
535*472cd20dSToomas Soome     // Set up DNSQuestion.
536*472cd20dSToomas Soome 
537*472cd20dSToomas Soome     if (EnableAllowExpired && (inParams->flags & kDNSServiceFlagsAllowExpiredAnswers))
538*472cd20dSToomas Soome     {
539*472cd20dSToomas Soome         q->allowExpired = AllowExpired_AllowExpiredAnswers;
540*472cd20dSToomas Soome     }
541*472cd20dSToomas Soome     else
542*472cd20dSToomas Soome     {
543*472cd20dSToomas Soome         q->allowExpired = AllowExpired_None;
544*472cd20dSToomas Soome     }
545*472cd20dSToomas Soome     q->ServiceID = inParams->serviceID;
546*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, AUDIT_TOKEN)
547*472cd20dSToomas Soome     q->inAppBrowserRequest = inParams->isInAppBrowserRequest;
548*472cd20dSToomas Soome     if (inParams->peerAuditToken)
549*472cd20dSToomas Soome     {
550*472cd20dSToomas Soome         q->peerAuditToken = *inParams->peerAuditToken;
551*472cd20dSToomas Soome     }
552*472cd20dSToomas Soome     if (inParams->delegatorAuditToken)
553*472cd20dSToomas Soome     {
554*472cd20dSToomas Soome         q->delegateAuditToken = *inParams->delegatorAuditToken;
555*472cd20dSToomas Soome     }
556*472cd20dSToomas Soome #endif
557*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
558*472cd20dSToomas Soome     if (inParams->resolverUUID)
559*472cd20dSToomas Soome     {
560*472cd20dSToomas Soome         mDNSPlatformMemCopy(q->ResolverUUID, inParams->resolverUUID, UUID_SIZE);
561*472cd20dSToomas Soome     }
562*472cd20dSToomas Soome #endif
563*472cd20dSToomas Soome     q->InterfaceID          = inParams->interfaceID;
564*472cd20dSToomas Soome     q->flags                = inParams->flags;
565*472cd20dSToomas Soome     AssignDomainName(&q->qname, inParams->qname);
566*472cd20dSToomas Soome     q->qtype                = inParams->qtype;
567*472cd20dSToomas Soome     q->qclass               = inParams->qclass;
568*472cd20dSToomas Soome     q->LongLived            = (inParams->flags & kDNSServiceFlagsLongLivedQuery)            ? mDNStrue : mDNSfalse;
569*472cd20dSToomas Soome     q->ForceMCast           = (inParams->flags & kDNSServiceFlagsForceMulticast)            ? mDNStrue : mDNSfalse;
570*472cd20dSToomas Soome     q->ReturnIntermed       = (inParams->flags & kDNSServiceFlagsReturnIntermediates)       ? mDNStrue : mDNSfalse;
571*472cd20dSToomas Soome     q->SuppressUnusable     = (inParams->flags & kDNSServiceFlagsSuppressUnusable)          ? mDNStrue : mDNSfalse;
572*472cd20dSToomas Soome     q->TimeoutQuestion      = (inParams->flags & kDNSServiceFlagsTimeout)                   ? mDNStrue : mDNSfalse;
573*472cd20dSToomas Soome     q->UseBackgroundTraffic = (inParams->flags & kDNSServiceFlagsBackgroundTrafficClass)    ? mDNStrue : mDNSfalse;
574*472cd20dSToomas Soome     q->AppendSearchDomains  = inParams->appendSearchDomains;
575*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
576*472cd20dSToomas Soome     q->RequireEncryption    = inParams->needEncryption;
577*472cd20dSToomas Soome     q->CustomID             = inParams->customID;
578*472cd20dSToomas Soome #endif
579*472cd20dSToomas Soome     q->InitialCacheMiss     = mDNSfalse;
580*472cd20dSToomas Soome 
581*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
582*472cd20dSToomas Soome     err = initialize_dnssec_status_t(&q->DNSSECStatus, inParams->qname, inParams->qtype, inParams->flags, inResultContext);
583*472cd20dSToomas Soome     require_action(err == mStatus_NoError, exit, log_debug("initialize_dnssec_status failed; error_description='%s'", mStatusDescription(err)));
584*472cd20dSToomas Soome #endif // MDNSRESPONDER_SUPPORTS(APPLE, DNSSECv2)
585*472cd20dSToomas Soome 
586*472cd20dSToomas Soome     q->pid              = inParams->effectivePID;
587*472cd20dSToomas Soome     if (inParams->effectiveUUID)
588*472cd20dSToomas Soome     {
589*472cd20dSToomas Soome         mDNSPlatformMemCopy(q->uuid, inParams->effectiveUUID, UUID_SIZE);
590*472cd20dSToomas Soome     }
591*472cd20dSToomas Soome     q->euid             = inParams->peerUID;
592*472cd20dSToomas Soome     q->request_id       = inParams->requestID;
593*472cd20dSToomas Soome     q->QuestionCallback = QueryRecordOpCallback;
594*472cd20dSToomas Soome     q->ResetHandler     = QueryRecordOpResetHandler;
595*472cd20dSToomas Soome 
596*472cd20dSToomas Soome     // For single label queries that are not fully qualified, look at /etc/hosts, cache and try search domains before trying
597*472cd20dSToomas Soome     // them on the wire as a single label query. - Mohan
598*472cd20dSToomas Soome 
599*472cd20dSToomas Soome     if (q->AppendSearchDomains && DomainNameIsSingleLabel(inOp->qname)) q->InterfaceID = mDNSInterface_LocalOnly;
600*472cd20dSToomas Soome     err = QueryRecordOpStartQuestion(inOp, q);
601*472cd20dSToomas Soome     if (err) goto exit;
602*472cd20dSToomas Soome 
603*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
604*472cd20dSToomas Soome     if (callExternalHelpers(q->InterfaceID, &q->qname, q->flags))
605*472cd20dSToomas Soome     {
606*472cd20dSToomas Soome         external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, q->flags, q->pid);
607*472cd20dSToomas Soome     }
608*472cd20dSToomas Soome #endif
609*472cd20dSToomas Soome 
610*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
611*472cd20dSToomas Soome     if ((RecordTypeIsAddress(q->qtype) || VALID_MSAD_SRV(&inOp->q)) && !q->ForceMCast &&
612*472cd20dSToomas Soome         SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain))
613*472cd20dSToomas Soome     {
614*472cd20dSToomas Soome         DNSQuestion *       q2;
615*472cd20dSToomas Soome 
616*472cd20dSToomas Soome         q2 = (DNSQuestion *) mDNSPlatformMemAllocate((mDNSu32)sizeof(*inOp->q2));
617*472cd20dSToomas Soome         if (!q2)
618*472cd20dSToomas Soome         {
619*472cd20dSToomas Soome             err = mStatus_NoMemoryErr;
620*472cd20dSToomas Soome             goto exit;
621*472cd20dSToomas Soome         }
622*472cd20dSToomas Soome         inOp->q2 = q2;
623*472cd20dSToomas Soome 
624*472cd20dSToomas Soome         *q2 = *q;
625*472cd20dSToomas Soome         q2->IsUnicastDotLocal = mDNStrue;
626*472cd20dSToomas Soome 
627*472cd20dSToomas Soome         if ((CountLabels(&q2->qname) == 2) && !SameDomainName(&q2->qname, &ActiveDirectoryPrimaryDomain)
628*472cd20dSToomas Soome             && !DomainNameIsInSearchList(&q2->qname, mDNSfalse))
629*472cd20dSToomas Soome         {
630*472cd20dSToomas Soome             inOp->q2Type                = q2->qtype;
631*472cd20dSToomas Soome             inOp->q2LongLived           = q2->LongLived;
632*472cd20dSToomas Soome             inOp->q2ReturnIntermed      = q2->ReturnIntermed;
633*472cd20dSToomas Soome             inOp->q2TimeoutQuestion     = q2->TimeoutQuestion;
634*472cd20dSToomas Soome             inOp->q2AppendSearchDomains = q2->AppendSearchDomains;
635*472cd20dSToomas Soome 
636*472cd20dSToomas Soome             AssignDomainName(&q2->qname, &localdomain);
637*472cd20dSToomas Soome             q2->qtype                   = kDNSType_SOA;
638*472cd20dSToomas Soome             q2->LongLived               = mDNSfalse;
639*472cd20dSToomas Soome             q2->ReturnIntermed          = mDNStrue;
640*472cd20dSToomas Soome             q2->TimeoutQuestion         = mDNSfalse;
641*472cd20dSToomas Soome             q2->AppendSearchDomains     = mDNSfalse;
642*472cd20dSToomas Soome         }
643*472cd20dSToomas Soome 
644*472cd20dSToomas Soome         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
645*472cd20dSToomas Soome                "[R%u] QueryRecordOpStart: starting parallel unicast query for " PRI_DM_NAME " " PUB_S,
646*472cd20dSToomas Soome                inOp->reqID, DM_NAME_PARAM(&q2->qname), DNSTypeName(q2->qtype));
647*472cd20dSToomas Soome 
648*472cd20dSToomas Soome         err = QueryRecordOpStartQuestion(inOp, q2);
649*472cd20dSToomas Soome         if (err) goto exit;
650*472cd20dSToomas Soome     }
651*472cd20dSToomas Soome #endif
652*472cd20dSToomas Soome     err = mStatus_NoError;
653*472cd20dSToomas Soome 
654*472cd20dSToomas Soome exit:
655*472cd20dSToomas Soome     if (err) QueryRecordOpStop(inOp);
656*472cd20dSToomas Soome     return err;
657*472cd20dSToomas Soome }
658*472cd20dSToomas Soome 
QueryRecordOpStop(QueryRecordOp * op)659*472cd20dSToomas Soome mDNSlocal void QueryRecordOpStop(QueryRecordOp *op)
660*472cd20dSToomas Soome {
661*472cd20dSToomas Soome     if (op->q.QuestionContext)
662*472cd20dSToomas Soome     {
663*472cd20dSToomas Soome         QueryRecordOpStopQuestion(&op->q);
664*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
665*472cd20dSToomas Soome         if (callExternalHelpers(op->q.InterfaceID, op->qname, op->q.flags))
666*472cd20dSToomas Soome         {
667*472cd20dSToomas Soome             external_stop_browsing_for_service(op->q.InterfaceID, &op->q.qname, op->q.qtype, op->q.flags, op->q.pid);
668*472cd20dSToomas Soome         }
669*472cd20dSToomas Soome #endif
670*472cd20dSToomas Soome     }
671*472cd20dSToomas Soome     if (op->qname)
672*472cd20dSToomas Soome     {
673*472cd20dSToomas Soome         mDNSPlatformMemFree(op->qname);
674*472cd20dSToomas Soome         op->qname = mDNSNULL;
675*472cd20dSToomas Soome     }
676*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
677*472cd20dSToomas Soome     if (op->q2)
678*472cd20dSToomas Soome     {
679*472cd20dSToomas Soome         if (op->q2->QuestionContext) QueryRecordOpStopQuestion(op->q2);
680*472cd20dSToomas Soome         mDNSPlatformMemFree(op->q2);
681*472cd20dSToomas Soome         op->q2 = mDNSNULL;
682*472cd20dSToomas Soome     }
683*472cd20dSToomas Soome #endif
684*472cd20dSToomas Soome }
685*472cd20dSToomas Soome 
QueryRecordOpIsMulticast(const QueryRecordOp * op)686*472cd20dSToomas Soome mDNSlocal mDNSBool QueryRecordOpIsMulticast(const QueryRecordOp *op)
687*472cd20dSToomas Soome {
688*472cd20dSToomas Soome     return ((mDNSOpaque16IsZero(op->q.TargetQID) && (op->q.ThisQInterval > 0)) ? mDNStrue : mDNSfalse);
689*472cd20dSToomas Soome }
690*472cd20dSToomas Soome 
691*472cd20dSToomas Soome // GetTimeNow is a callback-safe alternative to mDNS_TimeNow(), which expects to be called with m->mDNS_busy == 0.
GetTimeNow(mDNS * m)692*472cd20dSToomas Soome mDNSlocal mDNSs32 GetTimeNow(mDNS *m)
693*472cd20dSToomas Soome {
694*472cd20dSToomas Soome     mDNSs32 time;
695*472cd20dSToomas Soome     mDNS_Lock(m);
696*472cd20dSToomas Soome     time = m->timenow;
697*472cd20dSToomas Soome     mDNS_Unlock(m);
698*472cd20dSToomas Soome     return time;
699*472cd20dSToomas Soome }
700*472cd20dSToomas Soome 
QueryRecordOpCallback(mDNS * m,DNSQuestion * inQuestion,const ResourceRecord * inAnswer,QC_result inAddRecord)701*472cd20dSToomas Soome mDNSlocal void QueryRecordOpCallback(mDNS *m, DNSQuestion *inQuestion, const ResourceRecord *inAnswer, QC_result inAddRecord)
702*472cd20dSToomas Soome {
703*472cd20dSToomas Soome     mStatus                     resultErr;
704*472cd20dSToomas Soome     QueryRecordOp *const        op = (QueryRecordOp *)inQuestion->QuestionContext;
705*472cd20dSToomas Soome     const domainname *          domain;
706*472cd20dSToomas Soome 
707*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
708*472cd20dSToomas Soome     if ((inQuestion == op->q2) && (inQuestion->qtype == kDNSType_SOA))
709*472cd20dSToomas Soome     {
710*472cd20dSToomas Soome         DNSQuestion * const     q2 = op->q2;
711*472cd20dSToomas Soome 
712*472cd20dSToomas Soome         if (inAnswer->rrtype != kDNSType_SOA) goto exit;
713*472cd20dSToomas Soome         QueryRecordOpStopQuestion(q2);
714*472cd20dSToomas Soome 
715*472cd20dSToomas Soome         // Restore DNSQuestion variables that were modified for the SOA query.
716*472cd20dSToomas Soome 
717*472cd20dSToomas Soome         q2->qtype               = op->q2Type;
718*472cd20dSToomas Soome         q2->LongLived           = op->q2LongLived;
719*472cd20dSToomas Soome         q2->ReturnIntermed      = op->q2ReturnIntermed;
720*472cd20dSToomas Soome         q2->TimeoutQuestion     = op->q2TimeoutQuestion;
721*472cd20dSToomas Soome         q2->AppendSearchDomains = op->q2AppendSearchDomains;
722*472cd20dSToomas Soome 
723*472cd20dSToomas Soome         if (inAnswer->RecordType != kDNSRecordTypePacketNegative)
724*472cd20dSToomas Soome         {
725*472cd20dSToomas Soome             QueryRecordOpRestartUnicastQuestion(op, q2, mDNSNULL);
726*472cd20dSToomas Soome         }
727*472cd20dSToomas Soome         else if (q2->AppendSearchDomains)
728*472cd20dSToomas Soome         {
729*472cd20dSToomas Soome             domain = NextSearchDomain(op);
730*472cd20dSToomas Soome             if (domain) QueryRecordOpRestartUnicastQuestion(op, q2, domain);
731*472cd20dSToomas Soome         }
732*472cd20dSToomas Soome         goto exit;
733*472cd20dSToomas Soome     }
734*472cd20dSToomas Soome #endif
735*472cd20dSToomas Soome 
736*472cd20dSToomas Soome     if (inAddRecord == QC_suppressed)
737*472cd20dSToomas Soome     {
738*472cd20dSToomas Soome         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
739*472cd20dSToomas Soome                "[R%u] QueryRecordOpCallback: Suppressed question " PRI_DM_NAME " (" PUB_S ")",
740*472cd20dSToomas Soome                op->reqID, DM_NAME_PARAM(&inQuestion->qname), DNSTypeName(inQuestion->qtype));
741*472cd20dSToomas Soome 
742*472cd20dSToomas Soome         resultErr = kDNSServiceErr_NoSuchRecord;
743*472cd20dSToomas Soome     }
744*472cd20dSToomas Soome     else if (inAnswer->RecordType == kDNSRecordTypePacketNegative)
745*472cd20dSToomas Soome     {
746*472cd20dSToomas Soome         if (inQuestion->TimeoutQuestion && ((GetTimeNow(m) - inQuestion->StopTime) >= 0))
747*472cd20dSToomas Soome         {
748*472cd20dSToomas Soome             LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
749*472cd20dSToomas Soome                    "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME " (" PUB_S ") timing out, InterfaceID %p",
750*472cd20dSToomas Soome                    op->reqID, DM_NAME_PARAM(&inQuestion->qname), DNSTypeName(inQuestion->qtype),
751*472cd20dSToomas Soome                    inQuestion->InterfaceID);
752*472cd20dSToomas Soome             resultErr = kDNSServiceErr_Timeout;
753*472cd20dSToomas Soome         }
754*472cd20dSToomas Soome         else
755*472cd20dSToomas Soome         {
756*472cd20dSToomas Soome             if (inQuestion->AppendSearchDomains && (op->searchListIndex >= 0) && inAddRecord)
757*472cd20dSToomas Soome             {
758*472cd20dSToomas Soome                 domain = NextSearchDomain(op);
759*472cd20dSToomas Soome                 if (domain || DomainNameIsSingleLabel(op->qname))
760*472cd20dSToomas Soome                 {
761*472cd20dSToomas Soome                     QueryRecordOpStopQuestion(inQuestion);
762*472cd20dSToomas Soome                     QueryRecordOpRestartUnicastQuestion(op, inQuestion, domain);
763*472cd20dSToomas Soome                     goto exit;
764*472cd20dSToomas Soome                 }
765*472cd20dSToomas Soome             }
766*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
767*472cd20dSToomas Soome             if (!inAnswer->InterfaceID && IsLocalDomain(inAnswer->name))
768*472cd20dSToomas Soome             {
769*472cd20dSToomas Soome                 if ((RecordTypeIsAddress(inQuestion->qtype) &&
770*472cd20dSToomas Soome                     (inAnswer->negativeRecordType == kNegativeRecordType_NoData)) ||
771*472cd20dSToomas Soome                     DomainNameIsInSearchList(&inQuestion->qname, mDNStrue))
772*472cd20dSToomas Soome                 {
773*472cd20dSToomas Soome                     LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
774*472cd20dSToomas Soome                            "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME " (" PUB_S ") answering local with negative unicast response",
775*472cd20dSToomas Soome                            op->reqID, DM_NAME_PARAM(&inQuestion->qname), DNSTypeName(inQuestion->qtype));
776*472cd20dSToomas Soome                 }
777*472cd20dSToomas Soome                 else
778*472cd20dSToomas Soome                 {
779*472cd20dSToomas Soome                     goto exit;
780*472cd20dSToomas Soome                 }
781*472cd20dSToomas Soome             }
782*472cd20dSToomas Soome #endif
783*472cd20dSToomas Soome             resultErr = kDNSServiceErr_NoSuchRecord;
784*472cd20dSToomas Soome         }
785*472cd20dSToomas Soome     }
786*472cd20dSToomas Soome     else
787*472cd20dSToomas Soome     {
788*472cd20dSToomas Soome         resultErr = kDNSServiceErr_NoError;
789*472cd20dSToomas Soome     }
790*472cd20dSToomas Soome 
791*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
792*472cd20dSToomas Soome     if ((resultErr != kDNSServiceErr_Timeout) && (inAddRecord == QC_add))
793*472cd20dSToomas Soome     {
794*472cd20dSToomas Soome         op->answered = mDNStrue;
795*472cd20dSToomas Soome     }
796*472cd20dSToomas Soome #endif
797*472cd20dSToomas Soome 
798*472cd20dSToomas Soome     if (op->resultHandler) op->resultHandler(m, inQuestion, inAnswer, inAddRecord, resultErr, op->resultContext);
799*472cd20dSToomas Soome     if (resultErr == kDNSServiceErr_Timeout) QueryRecordOpStopQuestion(inQuestion);
800*472cd20dSToomas Soome 
801*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
802*472cd20dSToomas Soome     NotifyWebContentFilter(inAnswer, inQuestion->euid);
803*472cd20dSToomas Soome #endif
804*472cd20dSToomas Soome 
805*472cd20dSToomas Soome exit:
806*472cd20dSToomas Soome     return;
807*472cd20dSToomas Soome }
808*472cd20dSToomas Soome 
QueryRecordOpResetHandler(DNSQuestion * inQuestion)809*472cd20dSToomas Soome mDNSlocal void QueryRecordOpResetHandler(DNSQuestion *inQuestion)
810*472cd20dSToomas Soome {
811*472cd20dSToomas Soome     QueryRecordOp *const        op = (QueryRecordOp *)inQuestion->QuestionContext;
812*472cd20dSToomas Soome 
813*472cd20dSToomas Soome     AssignDomainName(&inQuestion->qname, op->qname);
814*472cd20dSToomas Soome     if (inQuestion->AppendSearchDomains && DomainNameIsSingleLabel(op->qname))
815*472cd20dSToomas Soome     {
816*472cd20dSToomas Soome         inQuestion->InterfaceID = mDNSInterface_LocalOnly;
817*472cd20dSToomas Soome     }
818*472cd20dSToomas Soome     else
819*472cd20dSToomas Soome     {
820*472cd20dSToomas Soome         inQuestion->InterfaceID = op->interfaceID;
821*472cd20dSToomas Soome     }
822*472cd20dSToomas Soome     op->searchListIndex = 0;
823*472cd20dSToomas Soome }
824*472cd20dSToomas Soome 
QueryRecordOpStartQuestion(QueryRecordOp * inOp,DNSQuestion * inQuestion)825*472cd20dSToomas Soome mDNSlocal mStatus QueryRecordOpStartQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion)
826*472cd20dSToomas Soome {
827*472cd20dSToomas Soome     mStatus     err;
828*472cd20dSToomas Soome 
829*472cd20dSToomas Soome     inQuestion->QuestionContext = inOp;
830*472cd20dSToomas Soome     err = mDNS_StartQuery(&mDNSStorage, inQuestion);
831*472cd20dSToomas Soome     if (err)
832*472cd20dSToomas Soome     {
833*472cd20dSToomas Soome         LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
834*472cd20dSToomas Soome                "[R%u] ERROR: QueryRecordOpStartQuestion mDNS_StartQuery for " PRI_DM_NAME " " PUB_S " failed with error %d",
835*472cd20dSToomas Soome                inOp->reqID, DM_NAME_PARAM(&inQuestion->qname), DNSTypeName(inQuestion->qtype), err);
836*472cd20dSToomas Soome         inQuestion->QuestionContext = mDNSNULL;
837*472cd20dSToomas Soome     }
838*472cd20dSToomas Soome     return err;
839*472cd20dSToomas Soome }
840*472cd20dSToomas Soome 
QueryRecordOpStopQuestion(DNSQuestion * inQuestion)841*472cd20dSToomas Soome mDNSlocal mStatus QueryRecordOpStopQuestion(DNSQuestion *inQuestion)
842*472cd20dSToomas Soome {
843*472cd20dSToomas Soome     mStatus     err;
844*472cd20dSToomas Soome 
845*472cd20dSToomas Soome     err = mDNS_StopQuery(&mDNSStorage, inQuestion);
846*472cd20dSToomas Soome     inQuestion->QuestionContext = mDNSNULL;
847*472cd20dSToomas Soome     return err;
848*472cd20dSToomas Soome }
849*472cd20dSToomas Soome 
QueryRecordOpRestartUnicastQuestion(QueryRecordOp * inOp,DNSQuestion * inQuestion,const domainname * inSearchDomain)850*472cd20dSToomas Soome mDNSlocal mStatus QueryRecordOpRestartUnicastQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion,
851*472cd20dSToomas Soome     const domainname *inSearchDomain)
852*472cd20dSToomas Soome {
853*472cd20dSToomas Soome     mStatus     err;
854*472cd20dSToomas Soome 
855*472cd20dSToomas Soome     inQuestion->InterfaceID = inOp->interfaceID;
856*472cd20dSToomas Soome     AssignDomainName(&inQuestion->qname, inOp->qname);
857*472cd20dSToomas Soome     if (inSearchDomain) AppendDomainName(&inQuestion->qname, inSearchDomain);
858*472cd20dSToomas Soome     if (SameDomainLabel(LastLabel(&inQuestion->qname), (const mDNSu8 *)&localdomain))
859*472cd20dSToomas Soome     {
860*472cd20dSToomas Soome         inQuestion->IsUnicastDotLocal = mDNStrue;
861*472cd20dSToomas Soome     }
862*472cd20dSToomas Soome     else
863*472cd20dSToomas Soome     {
864*472cd20dSToomas Soome         inQuestion->IsUnicastDotLocal = mDNSfalse;
865*472cd20dSToomas Soome     }
866*472cd20dSToomas Soome     err = QueryRecordOpStartQuestion(inOp, inQuestion);
867*472cd20dSToomas Soome     return err;
868*472cd20dSToomas Soome }
869*472cd20dSToomas Soome 
InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex,mDNSInterfaceID * outInterfaceID)870*472cd20dSToomas Soome mDNSlocal mStatus InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex, mDNSInterfaceID *outInterfaceID)
871*472cd20dSToomas Soome {
872*472cd20dSToomas Soome     mStatus             err;
873*472cd20dSToomas Soome     mDNSInterfaceID     interfaceID;
874*472cd20dSToomas Soome 
875*472cd20dSToomas Soome     interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, inInterfaceIndex);
876*472cd20dSToomas Soome 
877*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
878*472cd20dSToomas Soome     // The request is scoped to a specific interface index, but the interface is not currently in our list.
879*472cd20dSToomas Soome     if ((inInterfaceIndex != kDNSServiceInterfaceIndexAny) && (interfaceID == mDNSInterface_Any))
880*472cd20dSToomas Soome     {
881*472cd20dSToomas Soome         static dispatch_once_t      getLoopbackIndexOnce = 0;
882*472cd20dSToomas Soome         static mDNSu32              loopbackIndex = 0;
883*472cd20dSToomas Soome 
884*472cd20dSToomas Soome         dispatch_once(&getLoopbackIndexOnce,
885*472cd20dSToomas Soome         ^{
886*472cd20dSToomas Soome             loopbackIndex = if_nametoindex("lo0");
887*472cd20dSToomas Soome         });
888*472cd20dSToomas Soome 
889*472cd20dSToomas Soome         // If it's one of the specially defined inteface index values, just return an error. Also, caller should return an
890*472cd20dSToomas Soome         // error immediately if lo0 is not configured into the current active interfaces. See <rdar://problem/21967160>.
891*472cd20dSToomas Soome         if ((inInterfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
892*472cd20dSToomas Soome             (inInterfaceIndex == kDNSServiceInterfaceIndexUnicast)   ||
893*472cd20dSToomas Soome             (inInterfaceIndex == kDNSServiceInterfaceIndexP2P)       ||
894*472cd20dSToomas Soome             (inInterfaceIndex == kDNSServiceInterfaceIndexBLE)       ||
895*472cd20dSToomas Soome             (inInterfaceIndex == loopbackIndex))
896*472cd20dSToomas Soome         {
897*472cd20dSToomas Soome             LogInfo("ERROR: bad interfaceIndex %d", inInterfaceIndex);
898*472cd20dSToomas Soome             err = mStatus_BadParamErr;
899*472cd20dSToomas Soome             goto exit;
900*472cd20dSToomas Soome         }
901*472cd20dSToomas Soome 
902*472cd20dSToomas Soome         // Otherwise, use the specified interface index value and the request will be applied to that interface when it
903*472cd20dSToomas Soome         // comes up.
904*472cd20dSToomas Soome         interfaceID = (mDNSInterfaceID)(uintptr_t)inInterfaceIndex;
905*472cd20dSToomas Soome         LogInfo("Query pending for interface index %d", inInterfaceIndex);
906*472cd20dSToomas Soome     }
907*472cd20dSToomas Soome #endif
908*472cd20dSToomas Soome 
909*472cd20dSToomas Soome     *outInterfaceID = interfaceID;
910*472cd20dSToomas Soome     err = mStatus_NoError;
911*472cd20dSToomas Soome 
912*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
913*472cd20dSToomas Soome exit:
914*472cd20dSToomas Soome #endif
915*472cd20dSToomas Soome     return err;
916*472cd20dSToomas Soome }
917*472cd20dSToomas Soome 
DomainNameIsSingleLabel(const domainname * inName)918*472cd20dSToomas Soome mDNSlocal mDNSBool DomainNameIsSingleLabel(const domainname *inName)
919*472cd20dSToomas Soome {
920*472cd20dSToomas Soome     const mDNSu8 *const     label = inName->c;
921*472cd20dSToomas Soome     return (((label[0] != 0) && (label[1 + label[0]] == 0)) ? mDNStrue : mDNSfalse);
922*472cd20dSToomas Soome }
923*472cd20dSToomas Soome 
StringEndsWithDot(const char * inString)924*472cd20dSToomas Soome mDNSlocal mDNSBool StringEndsWithDot(const char *inString)
925*472cd20dSToomas Soome {
926*472cd20dSToomas Soome     const char *        ptr;
927*472cd20dSToomas Soome     mDNSu32             escapeCount;
928*472cd20dSToomas Soome     mDNSBool            result;
929*472cd20dSToomas Soome 
930*472cd20dSToomas Soome     // Loop invariant: escapeCount is the number of consecutive escape characters that immediately precede *ptr.
931*472cd20dSToomas Soome     // - If escapeCount is even, then *ptr is immediately preceded by escapeCount / 2 consecutive literal backslash
932*472cd20dSToomas Soome     //   characters, so *ptr is not escaped.
933*472cd20dSToomas Soome     // - If escapeCount is odd, then *ptr is immediately preceded by (escapeCount - 1) / 2 consecutive literal backslash
934*472cd20dSToomas Soome     //   characters followed by an escape character, so *ptr is escaped.
935*472cd20dSToomas Soome     escapeCount = 0;
936*472cd20dSToomas Soome     result = mDNSfalse;
937*472cd20dSToomas Soome     for (ptr = inString; *ptr != '\0'; ptr++)
938*472cd20dSToomas Soome     {
939*472cd20dSToomas Soome         if (*ptr == '\\')
940*472cd20dSToomas Soome         {
941*472cd20dSToomas Soome             escapeCount++;
942*472cd20dSToomas Soome         }
943*472cd20dSToomas Soome         else
944*472cd20dSToomas Soome         {
945*472cd20dSToomas Soome             if ((*ptr == '.') && (ptr[1] == '\0'))
946*472cd20dSToomas Soome             {
947*472cd20dSToomas Soome                 if ((escapeCount % 2) == 0) result = mDNStrue;
948*472cd20dSToomas Soome                 break;
949*472cd20dSToomas Soome             }
950*472cd20dSToomas Soome             escapeCount = 0;
951*472cd20dSToomas Soome         }
952*472cd20dSToomas Soome     }
953*472cd20dSToomas Soome     return result;
954*472cd20dSToomas Soome }
955*472cd20dSToomas Soome 
NextSearchDomain(QueryRecordOp * inOp)956*472cd20dSToomas Soome mDNSlocal const domainname * NextSearchDomain(QueryRecordOp *inOp)
957*472cd20dSToomas Soome {
958*472cd20dSToomas Soome     const domainname *      domain;
959*472cd20dSToomas Soome 
960*472cd20dSToomas Soome     while ((domain = uDNS_GetNextSearchDomain(inOp->interfaceID, &inOp->searchListIndex, mDNSfalse)) != mDNSNULL)
961*472cd20dSToomas Soome     {
962*472cd20dSToomas Soome         if ((DomainNameLength(inOp->qname) - 1 + DomainNameLength(domain)) <= MAX_DOMAIN_NAME) break;
963*472cd20dSToomas Soome     }
964*472cd20dSToomas Soome     if (!domain) inOp->searchListIndex = -1;
965*472cd20dSToomas Soome     return domain;
966*472cd20dSToomas Soome }
967*472cd20dSToomas Soome 
968*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
DomainNameIsInSearchList(const domainname * inName,mDNSBool inExcludeLocal)969*472cd20dSToomas Soome mDNSlocal mDNSBool DomainNameIsInSearchList(const domainname *inName, mDNSBool inExcludeLocal)
970*472cd20dSToomas Soome {
971*472cd20dSToomas Soome     const SearchListElem *      item;
972*472cd20dSToomas Soome     int                         labelCount, domainLabelCount;
973*472cd20dSToomas Soome 
974*472cd20dSToomas Soome     labelCount = CountLabels(inName);
975*472cd20dSToomas Soome     for (item = SearchList; item; item = item->next)
976*472cd20dSToomas Soome     {
977*472cd20dSToomas Soome         if (inExcludeLocal && SameDomainName(&item->domain, &localdomain)) continue;
978*472cd20dSToomas Soome         domainLabelCount = CountLabels(&item->domain);
979*472cd20dSToomas Soome         if (labelCount >= domainLabelCount)
980*472cd20dSToomas Soome         {
981*472cd20dSToomas Soome             if (SameDomainName(&item->domain, SkipLeadingLabels(inName, (labelCount - domainLabelCount))))
982*472cd20dSToomas Soome             {
983*472cd20dSToomas Soome                 return mDNStrue;
984*472cd20dSToomas Soome             }
985*472cd20dSToomas Soome         }
986*472cd20dSToomas Soome     }
987*472cd20dSToomas Soome     return mDNSfalse;
988*472cd20dSToomas Soome }
989*472cd20dSToomas Soome #endif
990*472cd20dSToomas Soome 
991*472cd20dSToomas Soome #if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
NotifyWebContentFilter(const ResourceRecord * inAnswer,uid_t inUID)992*472cd20dSToomas Soome mDNSlocal void NotifyWebContentFilter(const ResourceRecord *inAnswer, uid_t inUID)
993*472cd20dSToomas Soome {
994*472cd20dSToomas Soome     if (WCFIsServerRunning)
995*472cd20dSToomas Soome     {
996*472cd20dSToomas Soome 		const mDNS *const m = &mDNSStorage;
997*472cd20dSToomas Soome 
998*472cd20dSToomas Soome         if (WCFIsServerRunning(m->WCF) && inAnswer->rdlength != 0)
999*472cd20dSToomas Soome         {
1000*472cd20dSToomas Soome 			struct sockaddr_storage addr;
1001*472cd20dSToomas Soome 			addr.ss_len = 0;
1002*472cd20dSToomas Soome 			if (inAnswer->rrtype == kDNSType_A || inAnswer->rrtype == kDNSType_AAAA)
1003*472cd20dSToomas Soome 			{
1004*472cd20dSToomas Soome 				if (inAnswer->rrtype == kDNSType_A)
1005*472cd20dSToomas Soome 				{
1006*472cd20dSToomas Soome 					struct sockaddr_in *const sin = (struct sockaddr_in *)&addr;
1007*472cd20dSToomas Soome 					sin->sin_port = 0;
1008*472cd20dSToomas Soome 					// Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
1009*472cd20dSToomas Soome 					// sin->sin_addr.s_addr = inAnswer->rdata->u.ipv4.NotAnInteger;
1010*472cd20dSToomas Soome 					if (!putRData(mDNSNULL, (mDNSu8 *)&sin->sin_addr, (mDNSu8 *)(&sin->sin_addr + sizeof(mDNSv4Addr)), inAnswer))
1011*472cd20dSToomas Soome 						LogMsg("NotifyWebContentFilter: WCF AF_INET putRData failed");
1012*472cd20dSToomas Soome 					else
1013*472cd20dSToomas Soome 					{
1014*472cd20dSToomas Soome 						addr.ss_len = sizeof (struct sockaddr_in);
1015*472cd20dSToomas Soome 						addr.ss_family = AF_INET;
1016*472cd20dSToomas Soome 					}
1017*472cd20dSToomas Soome 				}
1018*472cd20dSToomas Soome 				else if (inAnswer->rrtype == kDNSType_AAAA)
1019*472cd20dSToomas Soome 				{
1020*472cd20dSToomas Soome 					struct sockaddr_in6 *const sin6 = (struct sockaddr_in6 *)&addr;
1021*472cd20dSToomas Soome 					sin6->sin6_port = 0;
1022*472cd20dSToomas Soome 					// Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
1023*472cd20dSToomas Soome 					// sin6->sin6_addr.__u6_addr.__u6_addr32[0] = inAnswer->rdata->u.ipv6.l[0];
1024*472cd20dSToomas Soome 					// sin6->sin6_addr.__u6_addr.__u6_addr32[1] = inAnswer->rdata->u.ipv6.l[1];
1025*472cd20dSToomas Soome 					// sin6->sin6_addr.__u6_addr.__u6_addr32[2] = inAnswer->rdata->u.ipv6.l[2];
1026*472cd20dSToomas Soome 					// sin6->sin6_addr.__u6_addr.__u6_addr32[3] = inAnswer->rdata->u.ipv6.l[3];
1027*472cd20dSToomas Soome 					if (!putRData(mDNSNULL, (mDNSu8 *)&sin6->sin6_addr, (mDNSu8 *)(&sin6->sin6_addr + sizeof(mDNSv6Addr)), inAnswer))
1028*472cd20dSToomas Soome 						LogMsg("NotifyWebContentFilter: WCF AF_INET6 putRData failed");
1029*472cd20dSToomas Soome 					else
1030*472cd20dSToomas Soome 					{
1031*472cd20dSToomas Soome 						addr.ss_len = sizeof (struct sockaddr_in6);
1032*472cd20dSToomas Soome 						addr.ss_family = AF_INET6;
1033*472cd20dSToomas Soome 					}
1034*472cd20dSToomas Soome 				}
1035*472cd20dSToomas Soome 				if (addr.ss_len)
1036*472cd20dSToomas Soome 				{
1037*472cd20dSToomas Soome         			char name[MAX_ESCAPED_DOMAIN_NAME];
1038*472cd20dSToomas Soome         			ConvertDomainNameToCString(inAnswer->name, name);
1039*472cd20dSToomas Soome 
1040*472cd20dSToomas Soome 					debugf("NotifyWebContentFilter: Name %s, uid %u, addr length %d", name, inUID, addr.ss_len);
1041*472cd20dSToomas Soome 					if (WCFNameResolvesToAddr)
1042*472cd20dSToomas Soome 					{
1043*472cd20dSToomas Soome 						WCFNameResolvesToAddr(m->WCF, name, (struct sockaddr *)&addr, inUID);
1044*472cd20dSToomas Soome 					}
1045*472cd20dSToomas Soome 				}
1046*472cd20dSToomas Soome 			}
1047*472cd20dSToomas Soome 			else if (inAnswer->rrtype == kDNSType_CNAME)
1048*472cd20dSToomas Soome 			{
1049*472cd20dSToomas Soome 				domainname cname;
1050*472cd20dSToomas Soome         		char name[MAX_ESCAPED_DOMAIN_NAME];
1051*472cd20dSToomas Soome 				char cname_cstr[MAX_ESCAPED_DOMAIN_NAME];
1052*472cd20dSToomas Soome 
1053*472cd20dSToomas Soome 				if (!putRData(mDNSNULL, cname.c, (mDNSu8 *)(cname.c + MAX_DOMAIN_NAME), inAnswer))
1054*472cd20dSToomas Soome 					LogMsg("NotifyWebContentFilter: WCF CNAME putRData failed");
1055*472cd20dSToomas Soome 				else
1056*472cd20dSToomas Soome 				{
1057*472cd20dSToomas Soome         			ConvertDomainNameToCString(inAnswer->name, name);
1058*472cd20dSToomas Soome 					ConvertDomainNameToCString(&cname, cname_cstr);
1059*472cd20dSToomas Soome 					if (WCFNameResolvesToAddr)
1060*472cd20dSToomas Soome 					{
1061*472cd20dSToomas Soome 						WCFNameResolvesToName(m->WCF, name, cname_cstr, inUID);
1062*472cd20dSToomas Soome 					}
1063*472cd20dSToomas Soome 				}
1064*472cd20dSToomas Soome 			}
1065*472cd20dSToomas Soome         }
1066*472cd20dSToomas Soome     }
1067*472cd20dSToomas Soome }
1068*472cd20dSToomas Soome #endif
1069