]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSCore/dnsproxy.c
mDNSResponder-544.tar.gz
[apple/mdnsresponder.git] / mDNSCore / dnsproxy.c
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
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 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
115 mDNSexport 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
136 mDNSlocal 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.
169 mDNSlocal 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
186 mDNSlocal 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
234 again:
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
375 mDNSlocal 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
484 done:
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
499 mDNSlocal 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
531 mDNSlocal 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
554 mDNSlocal 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
571 mDNSlocal 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
730 mDNSexport 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
737 mDNSexport 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
769 mDNSexport 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
782 mDNSexport 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
796 mDNSexport 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
810 mDNSexport 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
824 mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf)
825 {
826 (void) m;
827 (void) IpIfArr;
828 (void) OpIf;
829 }
830 extern void DNSProxyTerminate(mDNS *const m)
831 {
832 (void) m;
833 }
834
835
836 #endif // UNICAST_DISABLED