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