source: rtems-libbsd/mDNSResponder/mDNSCore/dnsproxy.c @ a814950

55-freebsd-126-freebsd-12
Last change on this file since a814950 was a814950, checked in by Sebastian Huber <sebastian.huber@…>, on 09/19/18 at 06:55:35

mDNSResponder: Update to v765.50.9

The sources can be obtained via:

https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-765.50.9.tar.gz

Update #3522.

  • Property mode set to 100644
File size: 32.0 KB
Line 
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
53typedef struct DNSProxyClient_struct DNSProxyClient;
54
55struct DNSProxyClient_struct {
56
57    DNSProxyClient *next;
58    mDNSAddr    addr;               // Client's IP address
59    mDNSIPPort  port;               // Client's port number
60    mDNSOpaque16 msgid;             // DNS msg id
61    mDNSInterfaceID interfaceID;    // Interface on which we received the request
62    void *socket;                   // Return socket
63    mDNSBool tcp;                   // TCP or UDP ?
64    mDNSOpaque16 requestFlags;      // second 16 bit word in the DNSMessageHeader of the request
65    mDNSu8 *optRR;                  // EDNS0 option
66    mDNSu16 optLen;                 // Total Length of the EDNS0 option
67    mDNSu16 rcvBufSize;             // How much can the client receive ?
68    mDNSBool DNSSECOK;              // DNSSEC OK ?
69    void *context;                  // Platform context to be disposed if non-NULL
70    domainname qname;               // q->qname can't be used for duplicate check
71    DNSQuestion q;                  // as it can change underneath us for CNAMEs
72};
73
74#define MIN_DNS_MESSAGE_SIZE    512
75DNSProxyClient *DNSProxyClients;
76
77mDNSlocal void FreeDNSProxyClient(DNSProxyClient *pc)
78{
79    if (pc->optRR)
80        mDNSPlatformMemFree(pc->optRR);
81    mDNSPlatformMemFree(pc);
82}
83
84mDNSlocal mDNSBool ParseEDNS0(DNSProxyClient *pc, const mDNSu8 *ptr, int length, const mDNSu8 *limit)
85{
86    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
112mDNSexport 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
133mDNSlocal 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.
166mDNSlocal 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
183mDNSlocal 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
230again:
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
371mDNSlocal 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
482done:
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
497mDNSlocal 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
526mDNSlocal 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
549mDNSlocal 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
573mDNSlocal 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
733mDNSexport 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
740mDNSexport 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
773mDNSexport 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
786mDNSexport 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
800mDNSexport 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
814mDNSexport 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
828mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf)
829{
830    (void) m;
831    (void) IpIfArr;
832    (void) OpIf;
833}
834extern void DNSProxyTerminate(mDNS *const m)
835{
836    (void) m;
837}
838
839
840#endif // UNICAST_DISABLED
Note: See TracBrowser for help on using the repository browser.