Beispiel #1
0
        public DnsDatagram(dynamic jsonResponse)
        {
            _header = new DnsHeader(jsonResponse);

            {
                _question = new DnsQuestionRecord[_header.QDCOUNT];
                int i = 0;
                foreach (dynamic jsonQuestionRecord in jsonResponse.Question)
                {
                    _question[i++] = new DnsQuestionRecord(jsonQuestionRecord);
                }
            }

            if (jsonResponse.Answer == null)
            {
                _answer = new DnsResourceRecord[] { };
            }
            else
            {
                _answer = new DnsResourceRecord[_header.ANCOUNT];
                int i = 0;
                foreach (dynamic jsonAnswerRecord in jsonResponse.Answer)
                {
                    _answer[i++] = new DnsResourceRecord(jsonAnswerRecord);
                }
            }

            if (jsonResponse.Authority == null)
            {
                _authority = new DnsResourceRecord[] { };
            }
            else
            {
                _authority = new DnsResourceRecord[_header.NSCOUNT];
                int i = 0;
                foreach (dynamic jsonAuthorityRecord in jsonResponse.Authority)
                {
                    _authority[i++] = new DnsResourceRecord(jsonAuthorityRecord);
                }
            }

            if (jsonResponse.Additional == null)
            {
                _additional = new DnsResourceRecord[] { };
            }
            else
            {
                _additional = new DnsResourceRecord[_header.ARCOUNT];
                int i = 0;
                foreach (dynamic jsonAdditionalRecord in jsonResponse.Additional)
                {
                    _additional[i++] = new DnsResourceRecord(jsonAdditionalRecord);
                }
            }
        }
        internal DnsDatagram CloneRequest()
        {
            DnsQuestionRecord[] clonedQuestion = new DnsQuestionRecord[_question.Count];

            for (int i = 0; i < _question.Count; i++)
            {
                clonedQuestion[i] = _question[i].Clone();
            }

            return(new DnsDatagram(_ID, _QR == 1, _OPCODE, _AA == 1, _TC == 1, _RD == 1, _RA == 1, _AD == 1, _CD == 1, _RCODE, clonedQuestion, _answer, _authority, _additional));
        }
Beispiel #3
0
        private DnsDatagram QueryCache(DnsHeader header, DnsQuestionRecord question)
        {
            string domain = question.Name.ToLower();

            DnsResourceRecord[] records = GetRecords(domain, question.Type);
            if (records != null)
            {
                if (records[0].RDATA is DnsEmptyRecord)
                {
                    return(new DnsDatagram(new DnsHeader(header.Identifier, true, DnsOpcode.StandardQuery, false, false, header.RecursionDesired, true, false, false, DnsResponseCode.NoError, 1, 0, 1, 0), new DnsQuestionRecord[] { question }, new DnsResourceRecord[] { }, new DnsResourceRecord[] { (records[0].RDATA as DnsEmptyRecord).Authority }, new DnsResourceRecord[] { }));
                }

                if (records[0].RDATA is DnsNXRecord)
                {
                    return(new DnsDatagram(new DnsHeader(header.Identifier, true, DnsOpcode.StandardQuery, false, false, header.RecursionDesired, true, false, false, DnsResponseCode.NameError, 1, 0, 1, 0), new DnsQuestionRecord[] { question }, new DnsResourceRecord[] { }, new DnsResourceRecord[] { (records[0].RDATA as DnsNXRecord).Authority }, new DnsResourceRecord[] { }));
                }

                return(new DnsDatagram(new DnsHeader(header.Identifier, true, DnsOpcode.StandardQuery, false, false, header.RecursionDesired, true, false, false, DnsResponseCode.NoError, 1, (ushort)records.Length, 0, 0), new DnsQuestionRecord[] { question }, records, new DnsResourceRecord[] { }, new DnsResourceRecord[] { }));
            }

            DnsResourceRecord[] nameServers = GetNearestNameServers(domain);
            if (nameServers != null)
            {
                List <DnsResourceRecord> glueRecords = new List <DnsResourceRecord>();

                foreach (DnsResourceRecord nameServer in nameServers)
                {
                    string nsDomain = (nameServer.RDATA as DnsNSRecord).NSDomainName;

                    DnsResourceRecord[] glueAs = GetRecords(nsDomain, DnsResourceRecordType.A);
                    if (glueAs != null)
                    {
                        glueRecords.AddRange(glueAs);
                    }


                    DnsResourceRecord[] glueAAAAs = GetRecords(nsDomain, DnsResourceRecordType.AAAA);
                    if (glueAAAAs != null)
                    {
                        glueRecords.AddRange(glueAAAAs);
                    }
                }

                DnsResourceRecord[] additional = glueRecords.ToArray();

                return(new DnsDatagram(new DnsHeader(header.Identifier, true, DnsOpcode.StandardQuery, false, false, header.RecursionDesired, true, false, false, DnsResponseCode.NoError, 1, 0, (ushort)nameServers.Length, (ushort)additional.Length), new DnsQuestionRecord[] { question }, new DnsResourceRecord[] { }, nameServers, additional));
            }

            return(null);
        }
Beispiel #4
0
        public static DnsDatagram ResolveViaNameServers(string domain, DnsResourceRecordType queryType, NameServerAddress[] nameServers = null, IDnsCache cache = null, NetProxy proxy = null, bool preferIPv6 = false, bool tcp = false, int retries = 2, int maxStackCount = 10)
        {
            DnsQuestionRecord question;

            if (queryType == DnsResourceRecordType.PTR)
            {
                question = new DnsQuestionRecord(IPAddress.Parse(domain), DnsClass.IN);
            }
            else
            {
                question = new DnsQuestionRecord(domain, queryType, DnsClass.IN);
            }

            return(ResolveViaNameServers(question, nameServers, cache, proxy, preferIPv6, tcp, retries, maxStackCount));
        }
        internal DnsDatagram CloneHeadersAndQuestions()
        {
            DnsQuestionRecord[] clonedQuestion = new DnsQuestionRecord[_question.Count];

            for (int i = 0; i < _question.Count; i++)
            {
                clonedQuestion[i] = _question[i].Clone();
            }

            DnsDatagram datagram = new DnsDatagram(_ID, _QR == 1, _OPCODE, _AA == 1, _TC == 1, _RD == 1, _RA == 1, _AD == 1, _CD == 1, _RCODE, clonedQuestion, _answer, _authority, _additional);

            datagram._metadata = _metadata;

            return(datagram);
        }
        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj))
            {
                return(false);
            }

            if (ReferenceEquals(this, obj))
            {
                return(true);
            }

            DnsQuestionRecord other = obj as DnsQuestionRecord;

            if (other == null)
            {
                return(false);
            }

            if (!_name.Equals(other._name, StringComparison.OrdinalIgnoreCase))
            {
                return(false);
            }

            if (_type != other._type)
            {
                return(false);
            }

            if (_class != other._class)
            {
                return(false);
            }

            return(true);
        }
Beispiel #7
0
 public DnsDatagram Resolve(DnsQuestionRecord questionRecord)
 {
     return(Resolve(new DnsDatagram(new DnsHeader(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, 1, 0, 0, 0), new DnsQuestionRecord[] { questionRecord }, null, null, null)));
 }
Beispiel #8
0
        public static DnsDatagram ResolveViaNameServers(DnsQuestionRecord question, NameServerAddress[] nameServers = null, IDnsCache cache = null, NetProxy proxy = null, bool preferIPv6 = false, bool tcp = false, int retries = 2, int maxStackCount = 10)
        {
            if ((nameServers != null) && (nameServers.Length > 0))
            {
                //create copy of name servers array so that the values in original array are not messed due to shuffling feature
                NameServerAddress[] nameServersCopy = new NameServerAddress[nameServers.Length];
                Array.Copy(nameServers, nameServersCopy, nameServers.Length);
                nameServers = nameServersCopy;
            }

            Stack <ResolverData> resolverStack = new Stack <ResolverData>();
            int stackNameServerIndex           = 0;

            while (true) //stack loop
            {
                if (resolverStack.Count > maxStackCount)
                {
                    while (resolverStack.Count > 0)
                    {
                        ResolverData data = resolverStack.Pop();

                        question = data.Question;
                    }

                    throw new DnsClientException("DnsClient exceeded the maximum stack count to resolve the domain: " + question.Name);
                }

                if (cache != null)
                {
                    DnsDatagram request       = new DnsDatagram(new DnsHeader(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, 1, 0, 0, 0), new DnsQuestionRecord[] { question }, null, null, null);
                    DnsDatagram cacheResponse = cache.Query(request);

                    switch (cacheResponse.Header.RCODE)
                    {
                    case DnsResponseCode.NoError:
                        if (cacheResponse.Answer.Length > 0)
                        {
                            if (resolverStack.Count == 0)
                            {
                                return(cacheResponse);
                            }
                            else
                            {
                                ResolverData data = resolverStack.Pop();

                                question             = data.Question;
                                nameServers          = data.NameServers;
                                stackNameServerIndex = data.NameServerIndex;

                                switch (cacheResponse.Answer[0].Type)
                                {
                                case DnsResourceRecordType.AAAA:
                                    nameServers[stackNameServerIndex] = new NameServerAddress(nameServers[stackNameServerIndex].Domain, (cacheResponse.Answer[0].RDATA as DnsAAAARecord).Address);
                                    break;

                                case DnsResourceRecordType.A:
                                    nameServers[stackNameServerIndex] = new NameServerAddress(nameServers[stackNameServerIndex].Domain, (cacheResponse.Answer[0].RDATA as DnsARecord).Address);
                                    break;

                                default:
                                    //didnt find IP for current name server
                                    stackNameServerIndex++;         //increment to skip current name server
                                    break;
                                }

                                continue;     //stack loop
                            }
                        }

                        if (cacheResponse.Authority.Length > 0)
                        {
                            if (cacheResponse.Authority[0].Type == DnsResourceRecordType.SOA)
                            {
                                if (resolverStack.Count == 0)
                                {
                                    return(cacheResponse);
                                }
                                else
                                {
                                    if (question.Type == DnsResourceRecordType.AAAA)
                                    {
                                        question = new DnsQuestionRecord(question.Name, DnsResourceRecordType.A, question.Class);
                                    }
                                    else
                                    {
                                        //didnt find IP for current name server
                                        //pop and try next name server
                                        ResolverData data = resolverStack.Pop();

                                        question             = data.Question;
                                        nameServers          = data.NameServers;
                                        stackNameServerIndex = data.NameServerIndex + 1;     //increment to skip current name server
                                    }

                                    continue;     //to stack loop
                                }
                            }

                            if ((nameServers == null) || (nameServers.Length == 0))
                            {
                                NameServerAddress[] cacheNameServers = NameServerAddress.GetNameServersFromResponse(cacheResponse, preferIPv6, true);

                                if (cacheNameServers.Length > 0)
                                {
                                    nameServers = cacheNameServers;
                                }
                            }
                        }

                        break;

                    case DnsResponseCode.NameError:
                        if (resolverStack.Count == 0)
                        {
                            return(cacheResponse);
                        }
                        else
                        {
                            //current name server domain doesnt exists
                            //pop and try next name server
                            ResolverData data = resolverStack.Pop();

                            question             = data.Question;
                            nameServers          = data.NameServers;
                            stackNameServerIndex = data.NameServerIndex + 1; //increment to skip current name server

                            continue;                                        //stack loop
                        }
                    }
                }

                if ((nameServers == null) || (nameServers.Length == 0))
                {
                    //create copy of root name servers array so that the values in original array are not messed due to shuffling feature
                    if (preferIPv6)
                    {
                        nameServers = new NameServerAddress[ROOT_NAME_SERVERS_IPv6.Length];
                        Array.Copy(ROOT_NAME_SERVERS_IPv6, nameServers, ROOT_NAME_SERVERS_IPv6.Length);
                    }
                    else
                    {
                        nameServers = new NameServerAddress[ROOT_NAME_SERVERS_IPv4.Length];
                        Array.Copy(ROOT_NAME_SERVERS_IPv4, nameServers, ROOT_NAME_SERVERS_IPv4.Length);
                    }
                }

                NameServerAddress.Shuffle(nameServers);

                int hopCount = 0;
                while ((hopCount++) < MAX_HOPS) //resolver loop
                {
                    //copy and reset stack name server index since its one time use only after stack pop
                    int i = stackNameServerIndex;
                    stackNameServerIndex = 0;

                    //query name servers one by one
                    for (; i < nameServers.Length; i++) //retry next server loop
                    {
                        NameServerAddress currentNameServer = nameServers[i];

                        if (question.Name == currentNameServer.Domain)
                        {
                            continue; //obvious!
                        }
                        if (currentNameServer.EndPoint == null)
                        {
                            resolverStack.Push(new ResolverData(question, nameServers, i));

                            if (preferIPv6)
                            {
                                question = new DnsQuestionRecord(currentNameServer.Domain, DnsResourceRecordType.AAAA, question.Class);
                            }
                            else
                            {
                                question = new DnsQuestionRecord(currentNameServer.Domain, DnsResourceRecordType.A, question.Class);
                            }

                            nameServers = null;
                            goto stackLoop;
                        }

                        DnsClient client = new DnsClient(currentNameServer);

                        client._proxy      = proxy;
                        client._preferIPv6 = preferIPv6;
                        client._tcp        = tcp;
                        client._retries    = retries;

                        DnsDatagram request = new DnsDatagram(new DnsHeader(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, 1, 0, 0, 0), new DnsQuestionRecord[] { question }, null, null, null);
                        DnsDatagram response;

                        try
                        {
                            response = client.Resolve(request);
                        }
                        catch (DnsClientException)
                        {
                            continue; //resolver loop
                        }

                        if (response.Header.Truncation)
                        {
                            if (tcp)
                            {
                                return(response);
                            }

                            client._tcp = true;
                            response    = client.Resolve(request);
                        }

                        if (cache != null)
                        {
                            cache.CacheResponse(response);
                        }

                        switch (response.Header.RCODE)
                        {
                        case DnsResponseCode.NoError:
                            if (response.Answer.Length > 0)
                            {
                                if (!response.Answer[0].Name.Equals(question.Name, StringComparison.CurrentCultureIgnoreCase))
                                {
                                    continue;     //continue to next name server since current name server may be misconfigured
                                }
                                if (resolverStack.Count == 0)
                                {
                                    return(response);
                                }
                                else
                                {
                                    ResolverData data = resolverStack.Pop();

                                    question             = data.Question;
                                    nameServers          = data.NameServers;
                                    stackNameServerIndex = data.NameServerIndex;

                                    switch (response.Answer[0].Type)
                                    {
                                    case DnsResourceRecordType.AAAA:
                                        nameServers[stackNameServerIndex] = new NameServerAddress(nameServers[stackNameServerIndex].Domain, (response.Answer[0].RDATA as DnsAAAARecord).Address);
                                        break;

                                    case DnsResourceRecordType.A:
                                        nameServers[stackNameServerIndex] = new NameServerAddress(nameServers[stackNameServerIndex].Domain, (response.Answer[0].RDATA as DnsARecord).Address);
                                        break;

                                    default:
                                        //didnt find IP for current name server
                                        stackNameServerIndex++;         //increment to skip current name server
                                        break;
                                    }

                                    goto resolverLoop;
                                }
                            }

                            if (response.Authority.Length == 0)
                            {
                                continue;     //continue to next name server since current name server may be misconfigured
                            }
                            if (response.Authority[0].Type == DnsResourceRecordType.SOA)
                            {
                                //no entry for given type
                                if (resolverStack.Count == 0)
                                {
                                    return(response);
                                }
                                else
                                {
                                    if (question.Type == DnsResourceRecordType.AAAA)
                                    {
                                        question = new DnsQuestionRecord(question.Name, DnsResourceRecordType.A, question.Class);
                                    }
                                    else
                                    {
                                        //didnt find IP for current name server
                                        //pop and try next name server
                                        ResolverData data = resolverStack.Pop();

                                        question             = data.Question;
                                        nameServers          = data.NameServers;
                                        stackNameServerIndex = data.NameServerIndex + 1;     //increment to skip current name server
                                    }

                                    goto stackLoop;     //goto stack loop
                                }
                            }

                            nameServers = NameServerAddress.GetNameServersFromResponse(response, preferIPv6, false);

                            if (nameServers.Length == 0)
                            {
                                continue;     //continue to next name server since current name server may be misconfigured
                            }
                            goto resolverLoop;

                        case DnsResponseCode.NameError:
                            if (resolverStack.Count == 0)
                            {
                                return(response);
                            }
                            else
                            {
                                //current name server domain doesnt exists
                                //pop and try next name server
                                ResolverData data = resolverStack.Pop();

                                question             = data.Question;
                                nameServers          = data.NameServers;
                                stackNameServerIndex = data.NameServerIndex + 1; //increment to skip current name server

                                goto stackLoop;                                  //goto stack loop
                            }

                        default:
                            continue;     //continue to next name server since current name server may be misconfigured
                        }
                    }

                    if (resolverStack.Count == 0)
                    {
                        throw new DnsClientException("DnsClient failed to resolve the request: no response from name servers.");
                    }
                    else
                    {
                        //didnt find IP for current name server
                        //pop and try next name server
                        ResolverData data = resolverStack.Pop();

                        question             = data.Question;
                        nameServers          = data.NameServers;
                        stackNameServerIndex = data.NameServerIndex + 1; //increment to skip current name server

                        break;                                           //to stack loop
                    }

                    resolverLoop :;
                }

                stackLoop :;
            }
        }
Beispiel #9
0
 public ResolverData(DnsQuestionRecord question, NameServerAddress[] nameServers, int nameServerIndex)
 {
     this.Question        = question;
     this.NameServers     = nameServers;
     this.NameServerIndex = nameServerIndex;
 }
Beispiel #10
0
        public virtual DnsDatagram Query(DnsDatagram request, bool serveStale = false)
        {
            if (serveStale)
            {
                throw new NotImplementedException("DnsCache does not implement serve stale.");
            }

            DnsQuestionRecord question = request.Question[0];

            IReadOnlyList <DnsResourceRecord> answerRecords = GetRecords(question.Name, question.Type);

            if (answerRecords != null)
            {
                if (answerRecords[0].RDATA is DnsEmptyRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (answerRecords[0].RDATA as DnsEmptyRecord).Authority;

                    if (authority == null)
                    {
                        responseAuthority = Array.Empty <DnsResourceRecord>();
                    }
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, responseAuthority));
                }

                if (answerRecords[0].RDATA is DnsNXRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (answerRecords[0].RDATA as DnsNXRecord).Authority;

                    if (authority == null)
                    {
                        responseAuthority = Array.Empty <DnsResourceRecord>();
                    }
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NameError, request.Question, null, responseAuthority));
                }

                if (answerRecords[0].RDATA is DnsANYRecord)
                {
                    DnsANYRecord anyRR = answerRecords[0].RDATA as DnsANYRecord;
                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, anyRR.Records));
                }

                if (answerRecords[0].RDATA is DnsFailureRecord)
                {
                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, (answerRecords[0].RDATA as DnsFailureRecord).RCODE, request.Question));
                }

                IReadOnlyList <DnsResourceRecord> additionalRecords = null;

                switch (question.Type)
                {
                case DnsResourceRecordType.NS:
                case DnsResourceRecordType.MX:
                case DnsResourceRecordType.SRV:
                    additionalRecords = GetAdditionalRecords(answerRecords);
                    break;
                }

                return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answerRecords, null, additionalRecords));
            }

            IReadOnlyList <DnsResourceRecord> closestAuthority = GetClosestNameServers(question.Name);

            if (closestAuthority != null)
            {
                IReadOnlyList <DnsResourceRecord> additionalRecords = GetAdditionalRecords(closestAuthority);

                return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, closestAuthority, additionalRecords));
            }

            return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.Refused, request.Question));
        }
Beispiel #11
0
        public virtual DnsDatagram Query(DnsDatagram request, bool serveStale = false)
        {
            if (serveStale)
            {
                throw new NotImplementedException("DnsCache does not implement serve stale.");
            }

            DnsQuestionRecord question = request.Question[0];

            IReadOnlyList <DnsResourceRecord> answerRecords = GetRecords(question.Name, question.Type);

            if (answerRecords != null)
            {
                if (answerRecords[0].RDATA is DnsEmptyRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (answerRecords[0].RDATA as DnsEmptyRecord).Authority;

                    if (authority == null)
                    {
                        responseAuthority = Array.Empty <DnsResourceRecord>();
                    }
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, responseAuthority));
                }

                if (answerRecords[0].RDATA is DnsNXRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (answerRecords[0].RDATA as DnsNXRecord).Authority;

                    if (authority == null)
                    {
                        responseAuthority = Array.Empty <DnsResourceRecord>();
                    }
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NameError, request.Question, null, responseAuthority));
                }

                if (answerRecords[0].RDATA is DnsANYRecord)
                {
                    DnsANYRecord anyRR = answerRecords[0].RDATA as DnsANYRecord;
                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, anyRR.Records));
                }

                if (answerRecords[0].RDATA is DnsFailureRecord)
                {
                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, (answerRecords[0].RDATA as DnsFailureRecord).RCODE, request.Question));
                }

                return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answerRecords));
            }

            string currentZone = question.Name;

            while (currentZone != null)
            {
                IReadOnlyList <DnsResourceRecord> nameServers = GetClosestNameServers(currentZone);
                if (nameServers == null)
                {
                    break;
                }

                List <DnsResourceRecord> glueRecords = new List <DnsResourceRecord>();

                foreach (DnsResourceRecord nameServer in nameServers)
                {
                    string nsDomain = (nameServer.RDATA as DnsNSRecord).NameServer;

                    IReadOnlyList <DnsResourceRecord> glueAs = GetRecords(nsDomain, DnsResourceRecordType.A);
                    if ((glueAs != null) && (glueAs.Count > 0) && (glueAs[0].RDATA is DnsARecord))
                    {
                        glueRecords.AddRange(glueAs);
                    }

                    IReadOnlyList <DnsResourceRecord> glueAAAAs = GetRecords(nsDomain, DnsResourceRecordType.AAAA);
                    if ((glueAAAAs != null) && (glueAAAAs.Count > 0) && (glueAAAAs[0].RDATA is DnsAAAARecord))
                    {
                        glueRecords.AddRange(glueAAAAs);
                    }
                }

                if (glueRecords.Count > 0)
                {
                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, nameServers, glueRecords));
                }

                currentZone = GetParentZone(currentZone);
            }

            return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.Refused, request.Question));
        }
        public override DnsDatagram Query(DnsDatagram request)
        {
            DnsQuestionRecord question = request.Question[0];

            DnsResourceRecord[] answerRecords = GetRecords(question.Name, question.Type);
            if (answerRecords != null)
            {
                if (answerRecords[0].RDATA is DnsEmptyRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (answerRecords[0].RDATA as DnsEmptyRecord).Authority;

                    if (authority == null)
                    {
                        responseAuthority = new DnsResourceRecord[] { }
                    }
                    ;
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.NoError, 1, 0, 1, 0), request.Question, new DnsResourceRecord[] { }, responseAuthority, new DnsResourceRecord[] { }));
                }

                if (answerRecords[0].RDATA is DnsNXRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (answerRecords[0].RDATA as DnsNXRecord).Authority;

                    if (authority == null)
                    {
                        responseAuthority = new DnsResourceRecord[] { }
                    }
                    ;
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.NameError, 1, 0, 1, 0), request.Question, new DnsResourceRecord[] { }, responseAuthority, new DnsResourceRecord[] { }));
                }

                if (answerRecords[0].RDATA is DnsANYRecord)
                {
                    DnsANYRecord anyRR = answerRecords[0].RDATA as DnsANYRecord;
                    return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.NoError, 1, (ushort)anyRR.Records.Length, 0, 0), request.Question, anyRR.Records, new DnsResourceRecord[] { }, new DnsResourceRecord[] { }));
                }

                if (answerRecords[0].RDATA is DnsFailureRecord)
                {
                    return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, (answerRecords[0].RDATA as DnsFailureRecord).RCODE, 1, 0, 0, 0), request.Question, new DnsResourceRecord[] { }, new DnsResourceRecord[] { }, new DnsResourceRecord[] { }));
                }

                return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.NoError, 1, (ushort)answerRecords.Length, 0, 0), request.Question, answerRecords, new DnsResourceRecord[] { }, new DnsResourceRecord[] { }));
            }

            string currentZone = question.Name;

            while (currentZone != null)
            {
                DnsResourceRecord[] nameServers = GetClosestNameServers(currentZone);
                if (nameServers == null)
                {
                    break;
                }

                List <DnsResourceRecord> glueRecords = new List <DnsResourceRecord>();

                foreach (DnsResourceRecord nameServer in nameServers)
                {
                    string nsDomain = (nameServer.RDATA as DnsNSRecord).NSDomainName;

                    DnsResourceRecord[] glueAs = GetRecords(nsDomain, DnsResourceRecordType.A);
                    if ((glueAs != null) && (glueAs.Length > 0) && (glueAs[0].RDATA is DnsARecord))
                    {
                        glueRecords.AddRange(glueAs);
                    }

                    DnsResourceRecord[] glueAAAAs = GetRecords(nsDomain, DnsResourceRecordType.AAAA);
                    if ((glueAAAAs != null) && (glueAAAAs.Length > 0) && (glueAAAAs[0].RDATA is DnsAAAARecord))
                    {
                        glueRecords.AddRange(glueAAAAs);
                    }
                }

                if (glueRecords.Count > 0)
                {
                    DnsResourceRecord[] additional = glueRecords.ToArray();
                    return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.NoError, 1, 0, (ushort)nameServers.Length, (ushort)additional.Length), request.Question, new DnsResourceRecord[] { }, nameServers, additional));
                }

                currentZone = GetParentZone(currentZone);
            }

            return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.Refused, 1, 0, 0, 0), request.Question, new DnsResourceRecord[] { }, new DnsResourceRecord[] { }, new DnsResourceRecord[] { }));
        }