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

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 9449f15 was 9449f15, checked in by Sebastian Huber <sebastian.huber@…>, on 01/30/14 at 12:52:13

mDNS: Import

The sources can be obtained via:

http://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-544.tar.gz

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