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