1/* -*- Mode: C; tab-width: 4 -*- 2 * 3 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18#include "dnsproxy.h" 19 20#ifndef UNICAST_DISABLED 21 22// Implementation Notes 23// 24// DNS Proxy listens on port 53 (UDPv4v6 & TCPv4v6) for DNS queries. It handles only 25// the "Query" opcode of the DNS protocol described in RFC 1035. For all other opcodes, it returns 26// "Not Implemented" error. The platform interface mDNSPlatformInitDNSProxySkts 27// sets up the sockets and whenever it receives a packet, it calls ProxyTCPCallback or ProxyUDPCallback 28// defined here. For TCP socket, the platform does the "accept" and only sends the received packets 29// on the newly accepted socket. A single UDP socket (per address family) is used to send/recv 30// requests/responses from all clients. For TCP, there is one socket per request. Hence, there is some 31// extra state that needs to be disposed at the end. 32// 33// When a DNS request is received, ProxyCallbackCommon checks for malformed packet etc. and also checks 34// for duplicates, before creating DNSProxyClient state and starting a question with the "core" 35// (mDNS_StartQuery). When the callback for the question happens, it gathers all the necessary 36// resource records, constructs a response and sends it back to the client. 37// 38// - Question callback is called with only one resource record at a time. We need all the resource 39// records to construct the response. Hence, we lookup all the records ourselves. 40// 41// - The response may not fit the client's buffer size. In that case, we need to set the truncate bit 42// and the client would retry using TCP. 43// 44// - The client may have set the DNSSEC OK bit in the EDNS0 option and that means we also have to 45// return the RRSIGs or the NSEC records with the RRSIGs in the Additional section. We need to 46// ask the "core" to fetch the DNSSEC records and do the validation if the CD bit is not set. 47// 48// Once the response is sent to the client, the client state is disposed. When there is no response 49// from the "core", it eventually times out and we will not find any answers in the cache and we send a 50// "NXDomain" response back. Thus, we don't need any special timers to reap the client state in the case 51// of errors. 52 53typedef struct DNSProxyClient_struct DNSProxyClient; 54 55struct DNSProxyClient_struct { 56 57 DNSProxyClient *next; 58 mDNSAddr addr; // Client's IP address 59 mDNSIPPort port; // Client's port number 60 mDNSOpaque16 msgid; // DNS msg id 61 mDNSInterfaceID interfaceID; // Interface on which we received the request 62 void *socket; // Return socket 63 mDNSBool tcp; // TCP or UDP ? 64 mDNSOpaque16 requestFlags; // second 16 bit word in the DNSMessageHeader of the request 65 mDNSu8 *optRR; // EDNS0 option 66 mDNSu16 optLen; // Total Length of the EDNS0 option 67 mDNSu16 rcvBufSize; // How much can the client receive ? 68 mDNSBool DNSSECOK; // DNSSEC OK ? 69 void *context; // Platform context to be disposed if non-NULL 70 domainname qname; // q->qname can't be used for duplicate check 71 DNSQuestion q; // as it can change underneath us for CNAMEs 72}; 73 74#define MIN_DNS_MESSAGE_SIZE 512 75DNSProxyClient *DNSProxyClients; 76 77mDNSlocal void FreeDNSProxyClient(DNSProxyClient *pc) 78{ 79 if (pc->optRR) 80 mDNSPlatformMemFree(pc->optRR); 81 mDNSPlatformMemFree(pc); 82} 83 84mDNSlocal mDNSBool ParseEDNS0(DNSProxyClient *pc, const mDNSu8 *ptr, int length, const mDNSu8 *limit) 85{ 86 mDNSu16 rrtype, rrclass; 87 mDNSu8 rcode, version; 88 mDNSu16 flag; 89 90 if (ptr + length > limit) 91 { 92 LogInfo("ParseEDNS0: Not enough space in the packet"); 93 return mDNSfalse; 94 } 95 // Skip the root label 96 ptr++; 97 rrtype = (mDNSu16) ((mDNSu16)ptr[0] << 8 | ptr[1]); 98 if (rrtype != kDNSType_OPT) 99 { 100 LogInfo("ParseEDNS0: Not the right type %d", rrtype); 101 return mDNSfalse; 102 } 103 rrclass = (mDNSu16) ((mDNSu16)ptr[2] << 8 | ptr[3]); 104 rcode = ptr[4]; 105 version = ptr[5]; 106 flag = (mDNSu16) ((mDNSu16)ptr[6] << 8 | ptr[7]); 107 108 debugf("rrtype is %s, length is %d, rcode %d, version %d, flag 0x%x", DNSTypeName(rrtype), rrclass, rcode, version, flag); 109 pc->rcvBufSize = rrclass; 110 pc->DNSSECOK = ptr[6] & 0x80; 111 112 return mDNStrue; 113} 114 115mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit) 116{ 117 DNSProxyClient *pc = (DNSProxyClient *)q->QuestionContext; 118 119 (void) msg; 120 121 h->flags = pc->requestFlags; 122 if (pc->optRR) 123 { 124 if (ptr + pc->optLen > limit) 125 { 126 LogInfo("DNSProxySetAttributes: Cannot set EDNS0 option start %p, OptLen %d, end %p", ptr, pc->optLen, limit); 127 return ptr; 128 } 129 h->numAdditionals++; 130 mDNSPlatformMemCopy(ptr, pc->optRR, pc->optLen); 131 ptr += pc->optLen; 132 } 133 return ptr; 134} 135 136mDNSlocal mDNSu8 *AddEDNS0Option(mDNS *const m, mDNSu8 *ptr, mDNSu8 *limit) 137{ 138 int len = 4096; 139 140 if (ptr + 11 > limit) 141 { 142 LogInfo("AddEDNS0Option: not enough space"); 143 return mDNSNULL; 144 } 145 m->omsg.h.numAdditionals++; 146 ptr[0] = 0; 147 ptr[1] = (mDNSu8) (kDNSType_OPT >> 8); 148 ptr[2] = (mDNSu8) (kDNSType_OPT & 0xFF); 149 ptr[3] = (mDNSu8) (len >> 8); 150 ptr[4] = (mDNSu8) (len & 0xFF); 151 ptr[5] = 0; // rcode 152 ptr[6] = 0; // version 153 ptr[7] = 0; 154 ptr[8] = 0; // flags 155 ptr[9] = 0; // rdlength 156 ptr[10] = 0; // rdlength 157 158 debugf("AddEDNS0 option"); 159 160 return (ptr + 11); 161} 162 163// Currently RD and CD bit should be copied if present in the request or cleared if 164// not present in the request. RD bit is normally set in the response and hence the 165// cache reflects the right value. CD bit behaves differently. If the CD bit is set 166// the first time, the cache retains it, if it is present in response (assuming the 167// upstream server does it right). Next time through we should not use the cached 168// value of the CD bit blindly. It depends on whether it was in the request or not. 169mDNSlocal mDNSOpaque16 SetResponseFlags(DNSProxyClient *pc, const mDNSOpaque16 responseFlags) 170{ 171 mDNSOpaque16 rFlags = responseFlags; 172 173 if (pc->requestFlags.b[0] & kDNSFlag0_RD) 174 rFlags.b[0] |= kDNSFlag0_RD; 175 else 176 rFlags.b[0] &= ~kDNSFlag0_RD; 177 178 if (pc->requestFlags.b[1] & kDNSFlag1_CD) 179 rFlags.b[1] |= kDNSFlag1_CD; 180 else 181 rFlags.b[1] &= ~kDNSFlag1_CD; 182 183 return rFlags; 184} 185 186mDNSlocal mDNSu8 *AddResourceRecords(mDNS *const m, DNSProxyClient *pc, mDNSu8 **prevptr, mStatus *error) 187{ 188 mDNSu32 slot; 189 CacheGroup *cg; 190 CacheRecord *cr; 191 int len = sizeof(DNSMessageHeader); 192 mDNSu8 *orig = m->omsg.data; 193 mDNSBool first = mDNStrue; 194 mDNSu8 *ptr = mDNSNULL; 195 mDNSs32 now; 196 mDNSs32 ttl; 197 CacheRecord *nsec = mDNSNULL; 198 CacheRecord *soa = mDNSNULL; 199 CacheRecord *cname = mDNSNULL; 200 mDNSu8 *limit; 201 202 *error = mStatus_NoError; 203 *prevptr = mDNSNULL; 204 205 mDNS_Lock(m); 206 now = m->timenow; 207 mDNS_Unlock(m); 208 209 if (!pc->tcp) 210 { 211 if (!pc->rcvBufSize) 212 { 213 limit = m->omsg.data + MIN_DNS_MESSAGE_SIZE; 214 } 215 else 216 { 217 limit = (pc->rcvBufSize > AbsoluteMaxDNSMessageData ? m->omsg.data + AbsoluteMaxDNSMessageData : m->omsg.data + pc->rcvBufSize); 218 } 219 } 220 else 221 { 222 // For TCP, limit is not determined by EDNS0 but by 16 bit rdlength field and 223 // AbsoluteMaxDNSMessageData is smaller than 64k. 224 limit = m->omsg.data + AbsoluteMaxDNSMessageData; 225 } 226 LogInfo("AddResourceRecords: Limit is %d", limit - m->omsg.data); 227 228 if (!SameDomainName(&pc->qname, &pc->q.qname)) 229 { 230 AssignDomainName(&pc->q.qname, &pc->qname); 231 pc->q.qnamehash = DomainNameHashValue(&pc->q.qname); 232 } 233 234again: 235 nsec = soa = cname = mDNSNULL; 236 slot = HashSlot(&pc->q.qname); 237 238 cg = CacheGroupForName(m, slot, pc->q.qnamehash, &pc->q.qname); 239 if (!cg) 240 { 241 LogInfo("AddResourceRecords: CacheGroup not found"); 242 *error = mStatus_NoSuchRecord; 243 return mDNSNULL; 244 } 245 // Set ValidatingResponse so that you can get RRSIGs also matching 246 // the question 247 if (pc->DNSSECOK) 248 pc->q.ValidatingResponse = 1; 249 for (cr = cg->members; cr; cr = cr->next) 250 { 251 if (SameNameRecordAnswersQuestion(&cr->resrec, &pc->q)) 252 { 253 if (first) 254 { 255 // If this is the first time, initialize the header and the question. 256 // This code needs to be here so that we can use the responseFlags from the 257 // cache record 258 mDNSOpaque16 responseFlags = SetResponseFlags(pc, cr->responseFlags); 259 InitializeDNSMessage(&m->omsg.h, pc->msgid, responseFlags); 260 ptr = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &pc->qname, pc->q.qtype, pc->q.qclass); 261 if (!ptr) 262 { 263 LogInfo("AddResourceRecords: putQuestion NULL for %##s (%s)", &pc->qname.c, DNSTypeName(pc->q.qtype)); 264 return mDNSNULL; 265 } 266 first = mDNSfalse; 267 } 268 // - For NegativeAnswers there is nothing to add 269 // - If DNSSECOK is set, we also automatically lookup the RRSIGs which 270 // will also be returned. If the client is explicitly looking up 271 // a DNSSEC record (e.g., DNSKEY, DS) we should return the response. 272 // DNSSECOK bit only influences whether we add the RRSIG or not. 273 if (cr->resrec.RecordType != kDNSRecordTypePacketNegative) 274 { 275 LogInfo("AddResourceRecords: Answering question with %s", CRDisplayString(m, cr)); 276 ttl = cr->resrec.rroriginalttl - (now - cr->TimeRcvd) / mDNSPlatformOneSecond; 277 ptr = PutResourceRecordTTLWithLimit(&m->omsg, ptr, &m->omsg.h.numAnswers, &cr->resrec, ttl, limit); 278 if (!ptr) 279 { 280 *prevptr = orig; 281 return mDNSNULL; 282 } 283 len += (ptr - orig); 284 orig = ptr; 285 } 286 // If we have nsecs (wildcard expanded answer or negative response), add them 287 // in the additional section below if the DNSSECOK bit is set 288 if (pc->DNSSECOK && cr->nsec) 289 { 290 LogInfo("AddResourceRecords: nsec set for %s", CRDisplayString(m ,cr)); 291 nsec = cr->nsec; 292 } 293 if (cr->soa) 294 { 295 LogInfo("AddResourceRecords: soa set for %s", CRDisplayString(m ,cr)); 296 soa = cr->soa; 297 } 298 // If we are using CNAME to answer a question and CNAME is not the type we 299 // are looking for, note down the CNAME record so that we can follow them 300 // later. Before we follow the CNAME, print the RRSIGs and any nsec (wildcard 301 // expanded) if any. 302 if ((pc->q.qtype != cr->resrec.rrtype) && cr->resrec.rrtype == kDNSType_CNAME) 303 { 304 LogInfo("AddResourceRecords: cname set for %s", CRDisplayString(m ,cr)); 305 cname = cr; 306 } 307 } 308 } 309 // Along with the nsec records, we also cache the SOA record. For non-DNSSEC question, we need 310 // to send the SOA back. Normally we either cache the SOA record (non-DNSSEC question) pointed 311 // to by "cr->soa" or the NSEC/SOA records along with their RRSIGs (DNSSEC question) pointed to 312 // by "cr->nsec". Two cases: 313 // 314 // - if we issue a DNSSEC question followed by non-DNSSEC question for the same name, 315 // we only have the nsec records and we need to filter the SOA record alone for the 316 // non-DNSSEC questions. 317 // 318 // - if we issue a non-DNSSEC question followed by DNSSEC question for the same name, 319 // the "core" flushes the cache entry and re-issue the question with EDNS0/DOK bit and 320 // in this case we return all the DNSSEC records we have. 321 for (; nsec; nsec = nsec->next) 322 { 323 if (!pc->DNSSECOK && DNSSECRecordType(nsec->resrec.rrtype)) 324 continue; 325 LogInfo("AddResourceRecords:NSEC Answering question with %s", CRDisplayString(m, nsec)); 326 ttl = nsec->resrec.rroriginalttl - (now - nsec->TimeRcvd) / mDNSPlatformOneSecond; 327 ptr = PutResourceRecordTTLWithLimit(&m->omsg, ptr, &m->omsg.h.numAuthorities, &nsec->resrec, ttl, limit); 328 if (!ptr) 329 { 330 *prevptr = orig; 331 return mDNSNULL; 332 } 333 len += (ptr - orig); 334 orig = ptr; 335 } 336 if (soa) 337 { 338 LogInfo("AddResourceRecords: SOA Answering question with %s", CRDisplayString(m, soa)); 339 ptr = PutResourceRecordTTLWithLimit(&m->omsg, ptr, &m->omsg.h.numAuthorities, &soa->resrec, soa->resrec.rroriginalttl, limit); 340 if (!ptr) 341 { 342 *prevptr = orig; 343 return mDNSNULL; 344 } 345 len += (ptr - orig); 346 orig = ptr; 347 } 348 if (cname) 349 { 350 AssignDomainName(&pc->q.qname, &cname->resrec.rdata->u.name); 351 pc->q.qnamehash = DomainNameHashValue(&pc->q.qname); 352 goto again; 353 } 354 if (!ptr) 355 { 356 LogInfo("AddResourceRecords: Did not find any valid ResourceRecords"); 357 *error = mStatus_NoSuchRecord; 358 return mDNSNULL; 359 } 360 if (pc->rcvBufSize) 361 { 362 ptr = AddEDNS0Option(m, ptr, limit); 363 if (!ptr) 364 { 365 *prevptr = orig; 366 return mDNSNULL; 367 } 368 len += (ptr - orig); 369 orig = ptr; 370 } 371 LogInfo("AddResourceRecord: Added %d bytes to the packet", len); 372 return ptr; 373} 374 375mDNSlocal void ProxyClientCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord) 376{ 377 DNSProxyClient *pc = question->QuestionContext; 378 DNSProxyClient **ppc = &DNSProxyClients; 379 mDNSu8 *ptr; 380 mDNSu8 *prevptr; 381 mStatus error; 382 383 if (!AddRecord) 384 return; 385 386 LogInfo("ProxyClientCallback: ResourceRecord %s", RRDisplayString(m, answer)); 387 388 // We asked for validation and not timed out yet, then wait for the DNSSEC result. 389 // We have to set the AD bit in the response if it is secure which can't be done 390 // till we get the DNSSEC result back (indicated by QC_dnssec). 391 if (question->ValidationRequired) 392 { 393 mDNSs32 now; 394 395 mDNS_Lock(m); 396 now = m->timenow; 397 mDNS_Unlock(m); 398 if (((now - question->StopTime) < 0) && AddRecord != QC_dnssec) 399 { 400 LogInfo("ProxyClientCallback: No DNSSEC answer yet for Question %##s (%s), AddRecord %d, answer %s", question->qname.c, 401 DNSTypeName(question->qtype), AddRecord, RRDisplayString(m, answer)); 402 return; 403 } 404 } 405 406 if (answer->RecordType != kDNSRecordTypePacketNegative) 407 { 408 if (answer->rrtype != question->qtype) 409 { 410 // Wait till we get called for the real response 411 LogInfo("ProxyClientCallback: Received %s, not answering yet", RRDisplayString(m, answer)); 412 return; 413 } 414 } 415 ptr = AddResourceRecords(m, pc, &prevptr, &error); 416 if (!ptr) 417 { 418 LogInfo("ProxyClientCallback: AddResourceRecords NULL for %##s (%s)", &pc->qname.c, DNSTypeName(pc->q.qtype)); 419 if (error == mStatus_NoError && prevptr) 420 { 421 // No space to add the record. Set the Truncate bit for UDP. 422 // 423 // TBD: For TCP, we need to send the rest of the data. But finding out what is left 424 // is harder. We should allocate enough buffer in the first place to send all 425 // of the data. 426 if (!pc->tcp) 427 { 428 m->omsg.h.flags.b[0] |= kDNSFlag0_TC; 429 ptr = prevptr; 430 } 431 else 432 { 433 LogInfo("ProxyClientCallback: ERROR!! Not enough space to return in TCP for %##s (%s)", &pc->qname.c, DNSTypeName(pc->q.qtype)); 434 ptr = prevptr; 435 } 436 } 437 else 438 { 439 mDNSOpaque16 flags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery, kDNSFlag1_RC_ServFail } }; 440 // We could not find the record for some reason. Return a response, so that the client 441 // is not waiting forever. 442 LogInfo("ProxyClientCallback: No response"); 443 if (!mDNSOpaque16IsZero(pc->q.responseFlags)) 444 flags = pc->q.responseFlags; 445 InitializeDNSMessage(&m->omsg.h, pc->msgid, flags); 446 ptr = putQuestion(&m->omsg, m->omsg.data, m->omsg.data + AbsoluteMaxDNSMessageData, &pc->qname, pc->q.qtype, pc->q.qclass); 447 if (!ptr) 448 { 449 LogInfo("ProxyClientCallback: putQuestion NULL for %##s (%s)", &pc->qname.c, DNSTypeName(pc->q.qtype)); 450 goto done; 451 } 452 } 453 } 454 if (question->ValidationRequired) 455 { 456 if (question->ValidationState == DNSSECValDone && question->ValidationStatus == DNSSEC_Secure) 457 { 458 LogInfo("ProxyClientCallback: Setting AD bit for Question %##s (%s)", question->qname.c, DNSTypeName(question->qtype)); 459 m->omsg.h.flags.b[1] |= kDNSFlag1_AD; 460 } 461 else 462 { 463 // If some external resolver sets the AD bit and we did not validate the response securely, don't set 464 // the AD bit. It is possible that we did not see all the records that the upstream resolver saw or 465 // a buggy implementation somewhere. 466 if (m->omsg.h.flags.b[1] & kDNSFlag1_AD) 467 { 468 LogInfo("ProxyClientCallback: AD bit set in the response for response that was not validated locally %##s (%s)", 469 question->qname.c, DNSTypeName(question->qtype)); 470 m->omsg.h.flags.b[1] &= ~kDNSFlag1_AD; 471 } 472 } 473 } 474 475 if (!pc->tcp) 476 { 477 mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, (UDPSocket *)pc->socket, &pc->addr, pc->port, mDNSNULL, mDNSNULL, mDNSfalse); 478 } 479 else 480 { 481 mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &pc->addr, pc->port, (TCPSocket *)pc->socket, mDNSNULL, mDNSfalse); 482 } 483 484done: 485 mDNS_StopQuery(m, question); 486 487 while (*ppc && *ppc != pc) 488 ppc=&(*ppc)->next; 489 if (!*ppc) 490 { 491 LogMsg("ProxyClientCallback: question %##s (%s) not found", question->qname.c, DNSTypeName(question->qtype)); 492 return; 493 } 494 *ppc = pc->next; 495 mDNSPlatformDisposeProxyContext(pc->context); 496 FreeDNSProxyClient(pc); 497} 498 499mDNSlocal void SendError(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *dstaddr, 500 const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSBool tcp, void *context, mDNSu8 rcode) 501{ 502 int pktlen = (int)(end - (mDNSu8 *)pkt); 503 DNSMessage *msg = (DNSMessage *)pkt; 504 505 (void) InterfaceID; 506 507 // RFC 1035 requires that we copy the question back and RFC 2136 is okay with sending nothing 508 // in the body or send back whatever we get for updates. It is easy to return whatever we get 509 // in the question back to the responder. We return as much as we can fit in our standard 510 // output packet. 511 if (pktlen > AbsoluteMaxDNSMessageData) 512 pktlen = AbsoluteMaxDNSMessageData; 513 514 mDNSPlatformMemCopy(&m->omsg.h, &msg->h, sizeof(DNSMessageHeader)); 515 m->omsg.h.flags.b[0] |= kDNSFlag0_QR_Response; 516 m->omsg.h.flags.b[1] = rcode; 517 mDNSPlatformMemCopy(m->omsg.data, (mDNSu8 *)&msg->h.numQuestions, pktlen); 518 if (!tcp) 519 { 520 mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, mDNSInterface_Any, socket, dstaddr, dstport, mDNSNULL, mDNSNULL, 521 mDNSfalse); 522 } 523 else 524 { 525 mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, mDNSInterface_Any, mDNSNULL, dstaddr, dstport, (TCPSocket *)socket, 526 mDNSNULL, mDNSfalse); 527 } 528 mDNSPlatformDisposeProxyContext(context); 529} 530 531mDNSlocal DNSQuestion *IsDuplicateClient(const mDNS *const m, const mDNSAddr *const addr, const mDNSIPPort port, const mDNSOpaque16 id, 532 const DNSQuestion *const question) 533{ 534 DNSProxyClient *pc; 535 536 (void) m; // unused 537 538 for (pc = DNSProxyClients; pc; pc = pc->next) 539 { 540 if (mDNSSameAddress(&pc->addr, addr) && 541 mDNSSameIPPort(pc->port, port) && 542 mDNSSameOpaque16(pc->msgid, id) && 543 pc->q.qtype == question->qtype && 544 pc->q.qclass == question->qclass && 545 SameDomainName(&pc->qname, &question->qname)) 546 { 547 LogInfo("IsDuplicateClient: Found a duplicate client in the list"); 548 return(&pc->q); 549 } 550 } 551 return(mDNSNULL); 552} 553 554mDNSlocal mDNSBool CheckDNSProxyIpIntf(const mDNS *const m, mDNSInterfaceID InterfaceID) 555{ 556 int i; 557 mDNSu32 ip_ifindex = (mDNSu32)(unsigned long)InterfaceID; 558 559 LogInfo("CheckDNSProxyIpIntf: Stored Input Interface List: [%d] [%d] [%d] [%d] [%d]", m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2], 560 m->dp_ipintf[3], m->dp_ipintf[4]); 561 562 for (i = 0; i < MaxIp; i++) 563 { 564 if (ip_ifindex == m->dp_ipintf[i]) 565 return mDNStrue; 566 } 567 return mDNSfalse; 568 569} 570 571mDNSlocal void ProxyCallbackCommon(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr, 572 const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, mDNSBool tcp, void *context) 573{ 574 DNSMessage *msg = (DNSMessage *)pkt; 575 mDNSu8 QR_OP; 576 const mDNSu8 *ptr; 577 DNSQuestion q, *qptr; 578 DNSProxyClient *pc; 579 const mDNSu8 *optRR; 580 int optLen = 0; 581 DNSProxyClient **ppc = &DNSProxyClients; 582 583 (void) dstaddr; 584 (void) dstport; 585 586 debugf("ProxyCallbackCommon: DNS Query coming from InterfaceID %p", InterfaceID); 587 // Ignore if the DNS Query is not from a Valid Input InterfaceID 588 if (!CheckDNSProxyIpIntf(m, InterfaceID)) 589 return; 590 591 if ((unsigned)(end - (mDNSu8 *)pkt) < sizeof(DNSMessageHeader)) 592 { 593 debugf("ProxyCallbackCommon: DNS Message from %#a:%d to %#a:%d length %d too short", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt); 594 return; 595 } 596 597 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask); 598 if (QR_OP != kDNSFlag0_QR_Query) 599 { 600 LogInfo("ProxyCallbackCommon: Not a query(%d) for pkt from %#a:%d", QR_OP, srcaddr, mDNSVal16(srcport)); 601 SendError(m, socket, pkt, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_NotImpl); 602 return; 603 } 604 605 // Read the integer parts which are in IETF byte-order (MSB first, LSB second) 606 ptr = (mDNSu8 *)&msg->h.numQuestions; 607 msg->h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]); 608 msg->h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]); 609 msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]); 610 msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]); 611 612 if (msg->h.numQuestions != 1 || msg->h.numAnswers || msg->h.numAuthorities) 613 { 614 LogInfo("ProxyCallbackCommon: Malformed pkt from %#a:%d, Q:%d, An:%d, Au:%d", srcaddr, mDNSVal16(srcport), 615 msg->h.numQuestions, msg->h.numAnswers, msg->h.numAuthorities); 616 SendError(m, socket, pkt, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_FormErr); 617 return; 618 } 619 ptr = msg->data; 620 ptr = getQuestion(msg, ptr, end, InterfaceID, &q); 621 if (!ptr) 622 { 623 LogInfo("ProxyCallbackCommon: Question cannot be parsed for pkt from %#a:%d", srcaddr, mDNSVal16(srcport)); 624 SendError(m, socket, pkt, end, srcaddr, srcport, InterfaceID, tcp, context, kDNSFlag1_RC_FormErr); 625 return; 626 } 627 else 628 { 629 LogInfo("ProxyCallbackCommon: Question %##s (%s)", q.qname.c, DNSTypeName(q.qtype)); 630 } 631 ptr = LocateOptRR(msg, end, 0); 632 if (ptr) 633 { 634 optRR = ptr; 635 ptr = skipResourceRecord(msg, ptr, end); 636 // Be liberal and ignore the EDNS0 option if we can't parse it properly 637 if (!ptr) 638 { 639 LogInfo("ProxyCallbackCommon: EDNS0 cannot be parsed for pkt from %#a:%d, ignoring", srcaddr, mDNSVal16(srcport)); 640 } 641 else 642 { 643 optLen = ptr - optRR; 644 LogInfo("ProxyCallbackCommon: EDNS0 opt length %d present in Question %##s (%s)", optLen, q.qname.c, DNSTypeName(q.qtype)); 645 } 646 } 647 else 648 { 649 LogInfo("ProxyCallbackCommon: EDNS0 opt not present in Question %##s (%s), ptr %p", q.qname.c, DNSTypeName(q.qtype), ptr); 650 } 651 652 qptr = IsDuplicateClient(m, srcaddr, srcport, msg->h.id, &q); 653 if (qptr) 654 { 655 LogInfo("ProxyCallbackCommon: Found a duplicate for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport)); 656 return; 657 } 658 pc = mDNSPlatformMemAllocate(sizeof(DNSProxyClient)); 659 if (!pc) 660 { 661 LogMsg("ProxyCallbackCommon: Memory failure for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport)); 662 return; 663 } 664 mDNSPlatformMemZero(pc, sizeof(DNSProxyClient)); 665 pc->addr = *srcaddr; 666 pc->port = srcport; 667 pc->msgid = msg->h.id; 668 pc->interfaceID = InterfaceID; // input interface 669 pc->socket = socket; 670 pc->tcp = tcp; 671 pc->requestFlags = msg->h.flags; 672 pc->context = context; 673 AssignDomainName(&pc->qname, &q.qname); 674 if (optRR) 675 { 676 if (!ParseEDNS0(pc, optRR, optLen, end)) 677 { 678 LogInfo("ProxyCallbackCommon: Invalid EDNS0 option for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport)); 679 } 680 else 681 { 682 pc->optRR = mDNSPlatformMemAllocate(optLen); 683 if (!pc->optRR) 684 { 685 LogMsg("ProxyCallbackCommon: Memory failure for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport)); 686 FreeDNSProxyClient(pc); 687 return; 688 } 689 mDNSPlatformMemCopy(pc->optRR, optRR, optLen); 690 pc->optLen = optLen; 691 } 692 } 693 694 debugf("ProxyCallbackCommon: DNS Query forwarding to interface index %d", m->dp_opintf); 695 mDNS_SetupQuestion(&pc->q, (mDNSInterfaceID)(unsigned long)m->dp_opintf, &q.qname, q.qtype, ProxyClientCallback, pc); 696 pc->q.TimeoutQuestion = 1; 697 // Even though we don't care about intermediate responses, set ReturnIntermed so that 698 // we get the negative responses 699 pc->q.ReturnIntermed = mDNStrue; 700 pc->q.ProxyQuestion = mDNStrue; 701 pc->q.ProxyDNSSECOK = pc->DNSSECOK; 702 pc->q.responseFlags = zeroID; 703 if (pc->DNSSECOK) 704 { 705 if (!(msg->h.flags.b[1] & kDNSFlag1_CD) && pc->q.qtype != kDNSType_RRSIG && pc->q.qtype != kDNSQType_ANY) 706 { 707 LogInfo("ProxyCallbackCommon: Setting Validation required bit for %#a:%d, validating %##s (%s)", srcaddr, mDNSVal16(srcport), 708 q.qname.c, DNSTypeName(q.qtype)); 709 pc->q.ValidationRequired = DNSSEC_VALIDATION_SECURE; 710 } 711 else 712 { 713 LogInfo("ProxyCallbackCommon: CD bit not set OR not a valid type for %#a:%d, not validating %##s (%s)", srcaddr, mDNSVal16(srcport), 714 q.qname.c, DNSTypeName(q.qtype)); 715 } 716 } 717 else 718 { 719 LogInfo("ProxyCallbackCommon: DNSSEC OK bit not set for %#a:%d, not validating %##s (%s)", srcaddr, mDNSVal16(srcport), 720 q.qname.c, DNSTypeName(q.qtype)); 721 } 722 723 while (*ppc) 724 ppc = &((*ppc)->next); 725 *ppc = pc; 726 727 mDNS_StartQuery(m, &pc->q); 728} 729 730mDNSexport void ProxyUDPCallback(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr, 731 const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context) 732{ 733 LogInfo("ProxyUDPCallback: DNS Message from %#a:%d to %#a:%d length %d", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt); 734 ProxyCallbackCommon(m, socket, pkt, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, mDNSfalse, context); 735} 736 737mDNSexport void ProxyTCPCallback(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr, 738 const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context) 739{ 740 LogInfo("ProxyTCPCallback: DNS Message from %#a:%d to %#a:%d length %d", srcaddr, mDNSVal16(srcport), dstaddr, mDNSVal16(dstport), end - (mDNSu8 *)pkt); 741 // If the connection was closed from the other side, locate the client 742 // state and free it. 743 if ((end - (mDNSu8 *)pkt) == 0) 744 { 745 DNSProxyClient **ppc = &DNSProxyClients; 746 DNSProxyClient **prevpc; 747 748 prevpc = ppc; 749 while (*ppc && (*ppc)->socket != socket) 750 { 751 prevpc = ppc; 752 ppc=&(*ppc)->next; 753 } 754 if (!*ppc) 755 { 756 mDNSPlatformDisposeProxyContext(socket); 757 LogMsg("ProxyTCPCallback: socket cannot be found"); 758 return; 759 } 760 *prevpc = (*ppc)->next; 761 LogInfo("ProxyTCPCallback: free"); 762 mDNSPlatformDisposeProxyContext(socket); 763 FreeDNSProxyClient(*ppc); 764 return; 765 } 766 ProxyCallbackCommon(m, socket, pkt, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, mDNStrue, context); 767} 768 769mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf) 770{ 771 int i; 772 773 // Store DNSProxy Interface fields in mDNS struct 774 for (i = 0; i < MaxIp; i++) 775 m->dp_ipintf[i] = IpIfArr[i]; 776 m->dp_opintf = OpIf; 777 778 LogInfo("DNSProxyInit Storing interface list: Input [%d, %d, %d, %d, %d] Output [%d]", m->dp_ipintf[0], 779 m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4], m->dp_opintf); 780} 781 782mDNSexport void DNSProxyTerminate(mDNS *const m) 783{ 784 int i; 785 786 // Clear DNSProxy Interface fields from mDNS struct 787 for (i = 0; i < MaxIp; i++) 788 m->dp_ipintf[i] = 0; 789 m->dp_opintf = 0; 790 791 LogInfo("DNSProxyTerminate Cleared interface list: Input [%d, %d, %d, %d, %d] Output [%d]", m->dp_ipintf[0], 792 m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4], m->dp_opintf); 793} 794#else // UNICAST_DISABLED 795 796mDNSexport void ProxyUDPCallback(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context) 797{ 798 (void) m; 799 (void) socket; 800 (void) pkt; 801 (void) end; 802 (void) srcaddr; 803 (void) srcport; 804 (void) dstaddr; 805 (void) dstport; 806 (void) InterfaceID; 807 (void) context; 808} 809 810mDNSexport void ProxyTCPCallback(mDNS *const m, void *socket, void *const pkt, const mDNSu8 *const end, const mDNSAddr *const srcaddr, const mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID, void *context) 811{ 812 (void) m; 813 (void) socket; 814 (void) pkt; 815 (void) end; 816 (void) srcaddr; 817 (void) srcport; 818 (void) dstaddr; 819 (void) dstport; 820 (void) InterfaceID; 821 (void) context; 822} 823 824mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf) 825{ 826 (void) m; 827 (void) IpIfArr; 828 (void) OpIf; 829} 830extern void DNSProxyTerminate(mDNS *const m) 831{ 832 (void) m; 833} 834 835 836#endif // UNICAST_DISABLED 837