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