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

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

            DnsResourceRecord other = obj as DnsResourceRecord;

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

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

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

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

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

            return(this._data.Equals(other._data));
        }
Esempio n. 2
0
        private void ResolveAdditionalRecords(DnsResourceRecord refRecord, string domain, List <DnsResourceRecord> additionalRecords)
        {
            IReadOnlyList <DnsResourceRecord> glueRecords = GetGlueRecordsFrom(refRecord);

            if (glueRecords.Count > 0)
            {
                bool added = false;

                foreach (DnsResourceRecord glueRecord in glueRecords)
                {
                    if (!glueRecord.IsStale)
                    {
                        added = true;
                        additionalRecords.Add(glueRecord);
                    }
                }

                if (added)
                {
                    return;
                }
            }

            if (_cache.TryGetValue(domain.ToLower(), out DnsCacheEntry entry))
            {
                IReadOnlyList <DnsResourceRecord> glueAs = entry.QueryRecords(DnsResourceRecordType.A, true);
                if ((glueAs.Count > 0) && (glueAs[0].Type == DnsResourceRecordType.A))
                {
                    additionalRecords.AddRange(glueAs);
                }

                IReadOnlyList <DnsResourceRecord> glueAAAAs = entry.QueryRecords(DnsResourceRecordType.AAAA, true);
                if ((glueAAAAs.Count > 0) && (glueAAAAs[0].Type == DnsResourceRecordType.AAAA))
                {
                    additionalRecords.AddRange(glueAAAAs);
                }
            }
        }
Esempio n. 3
0
        private void ResolveAdditionalRecords(DnsResourceRecord refRecord, string domain, List <DnsResourceRecord> additionalRecords)
        {
            IReadOnlyList <DnsResourceRecord> glueRecords = GetGlueRecordsFrom(refRecord);

            if (glueRecords.Count > 0)
            {
                bool added = false;

                foreach (DnsResourceRecord glueRecord in glueRecords)
                {
                    if (!glueRecord.IsStale)
                    {
                        added = true;
                        additionalRecords.Add(glueRecord);
                    }
                }

                if (added)
                {
                    return;
                }
            }

            IReadOnlyList <DnsResourceRecord> glueAs = GetRecords(domain, DnsResourceRecordType.A);

            if ((glueAs != null) && (glueAs.Count > 0) && (glueAs[0].RDATA is DnsARecord))
            {
                additionalRecords.AddRange(glueAs);
            }

            IReadOnlyList <DnsResourceRecord> glueAAAAs = GetRecords(domain, DnsResourceRecordType.AAAA);

            if ((glueAAAAs != null) && (glueAAAAs.Count > 0) && (glueAAAAs[0].RDATA is DnsAAAARecord))
            {
                additionalRecords.AddRange(glueAAAAs);
            }
        }
Esempio n. 4
0
        public void CacheResponse(DnsDatagram response)
        {
            if (!response.Header.IsResponse)
            {
                return;
            }

            //combine all records in the response
            List <DnsResourceRecord> allRecords = new List <DnsResourceRecord>();

            switch (response.Header.RCODE)
            {
            case DnsResponseCode.NameError:
                if (response.Authority.Length > 0)
                {
                    DnsResourceRecord authority = response.Authority[0];
                    if (authority.Type == DnsResourceRecordType.SOA)
                    {
                        foreach (DnsQuestionRecord question in response.Question)
                        {
                            DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, DnsClass.IN, DEFAULT_RECORD_TTL, new DnsNXRecord(authority));
                            record.SetExpiry();

                            CacheEntry(question.Name, question.Type, new DnsResourceRecord[] { record });
                        }
                    }
                }
                break;

            case DnsResponseCode.NoError:
                if ((response.Answer.Length == 0) && (response.Authority.Length > 0))
                {
                    DnsResourceRecord authority = response.Authority[0];
                    if (authority.Type == DnsResourceRecordType.SOA)
                    {
                        foreach (DnsQuestionRecord question in response.Question)
                        {
                            DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, DnsClass.IN, DEFAULT_RECORD_TTL, new DnsEmptyRecord(authority));
                            record.SetExpiry();

                            CacheEntry(question.Name, question.Type, new DnsResourceRecord[] { record });
                        }
                    }
                }
                else
                {
                    allRecords.AddRange(response.Answer);
                }

                break;

            default:
                return;     //nothing to do
            }

            allRecords.AddRange(response.Authority);
            allRecords.AddRange(response.Additional);

            #region group all records by domain and type

            Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > cacheEntries = new Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > >();

            foreach (DnsResourceRecord record in allRecords)
            {
                Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > cacheTypeEntries;

                if (cacheEntries.ContainsKey(record.Name))
                {
                    cacheTypeEntries = cacheEntries[record.Name];
                }
                else
                {
                    cacheTypeEntries = new Dictionary <DnsResourceRecordType, List <DnsResourceRecord> >();
                    cacheEntries.Add(record.Name, cacheTypeEntries);
                }

                List <DnsResourceRecord> cacheRREntries;

                if (cacheTypeEntries.ContainsKey(record.Type))
                {
                    cacheRREntries = cacheTypeEntries[record.Type];
                }
                else
                {
                    cacheRREntries = new List <DnsResourceRecord>();
                    cacheTypeEntries.Add(record.Type, cacheRREntries);
                }

                cacheRREntries.Add(record);
            }

            #endregion

            //add grouped entries into cache
            foreach (KeyValuePair <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > cacheEntry in cacheEntries)
            {
                string domain = cacheEntry.Key;

                foreach (KeyValuePair <DnsResourceRecordType, List <DnsResourceRecord> > cacheTypeEntry in cacheEntry.Value)
                {
                    DnsResourceRecordType type    = cacheTypeEntry.Key;
                    DnsResourceRecord[]   records = cacheTypeEntry.Value.ToArray();

                    foreach (DnsResourceRecord record in records)
                    {
                        record.SetExpiry();
                    }

                    CacheEntry(domain, type, records);
                }
            }

            //cache for ANY request
            if (response.Question[0].Type == DnsResourceRecordType.ANY)
            {
                CacheEntry(response.Question[0].Name, DnsResourceRecordType.ANY, response.Answer);
            }
        }
Esempio n. 5
0
        public void CacheResponse(DnsDatagram response)
        {
            if (!response.Header.IsResponse || response.Header.Truncation || (response.Question.Length == 0))
            {
                return; //ineligible response
            }
            switch (response.Header.RCODE)
            {
            case DnsResponseCode.NoError:
            case DnsResponseCode.NameError:
                //cache response after this switch
                break;

            default:
                //cache as failure record with RCODE
                foreach (DnsQuestionRecord question in response.Question)
                {
                    DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, question.Class, _negativeRecordTtl, new DnsFailureRecord(response.Header.RCODE));
                    record.SetExpiry(_minimumRecordTtl, _serveStaleTtl);

                    CacheRecords(new DnsResourceRecord[] { record });
                }

                return;
            }

            //cache only NoError and NameError responses

            //combine all records in the response
            List <DnsResourceRecord> cachableRecords = new List <DnsResourceRecord>();

            //get cachable answer records
            foreach (DnsQuestionRecord question in response.Question)
            {
                string qName = question.Name;

                foreach (DnsResourceRecord answer in response.Answer)
                {
                    if (answer.Name.Equals(qName, StringComparison.OrdinalIgnoreCase))
                    {
                        cachableRecords.Add(answer);

                        switch (answer.Type)
                        {
                        case DnsResourceRecordType.CNAME:
                            qName = (answer.RDATA as DnsCNAMERecord).CNAMEDomainName;
                            break;

                        case DnsResourceRecordType.NS:
                            string nsDomain = (answer.RDATA as DnsNSRecord).NSDomainName;

                            if (!nsDomain.EndsWith(".root-servers.net", StringComparison.OrdinalIgnoreCase))
                            {
                                foreach (DnsResourceRecord record in response.Additional)
                                {
                                    if (nsDomain.Equals(record.Name, StringComparison.OrdinalIgnoreCase))
                                    {
                                        cachableRecords.Add(record);
                                    }
                                }
                            }

                            break;

                        case DnsResourceRecordType.MX:
                            string mxExchange = (answer.RDATA as DnsMXRecord).Exchange;

                            foreach (DnsResourceRecord record in response.Additional)
                            {
                                if (mxExchange.Equals(record.Name, StringComparison.OrdinalIgnoreCase))
                                {
                                    cachableRecords.Add(record);
                                }
                            }

                            break;
                        }
                    }
                }
            }

            //get cachable authority records
            if (response.Authority.Length > 0)
            {
                DnsResourceRecord authority = response.Authority[0];
                if (authority.Type == DnsResourceRecordType.SOA)
                {
                    authority.SetExpiry(_minimumRecordTtl, _serveStaleTtl);

                    if (response.Answer.Length == 0)
                    {
                        //empty response with authority
                        foreach (DnsQuestionRecord question in response.Question)
                        {
                            if (question.Name.Equals(authority.Name, StringComparison.OrdinalIgnoreCase) || question.Name.EndsWith("." + authority.Name, StringComparison.OrdinalIgnoreCase) || authority.Name.Equals("", StringComparison.OrdinalIgnoreCase))
                            {
                                DnsResourceRecord record = null;

                                switch (response.Header.RCODE)
                                {
                                case DnsResponseCode.NameError:
                                    record = new DnsResourceRecord(question.Name, question.Type, question.Class, (authority.RDATA as DnsSOARecord).Minimum, new DnsNXRecord(authority));
                                    break;

                                case DnsResponseCode.NoError:
                                    record = new DnsResourceRecord(question.Name, question.Type, question.Class, (authority.RDATA as DnsSOARecord).Minimum, new DnsEmptyRecord(authority));
                                    break;
                                }

                                if (record != null)
                                {
                                    record.SetExpiry(_minimumRecordTtl, _serveStaleTtl);

                                    CacheRecords(new DnsResourceRecord[] { record });
                                }
                            }
                        }
                    }
                    else
                    {
                        //answer response with authority
                        DnsResourceRecord lastAnswer = response.Answer[response.Answer.Length - 1];
                        if (lastAnswer.Type == DnsResourceRecordType.CNAME)
                        {
                            foreach (DnsQuestionRecord question in response.Question)
                            {
                                if (question.Name.Equals(authority.Name, StringComparison.OrdinalIgnoreCase) || question.Name.EndsWith("." + authority.Name, StringComparison.OrdinalIgnoreCase))
                                {
                                    DnsResourceRecord record = null;

                                    switch (response.Header.RCODE)
                                    {
                                    case DnsResponseCode.NameError:
                                        record = new DnsResourceRecord((lastAnswer.RDATA as DnsCNAMERecord).CNAMEDomainName, question.Type, question.Class, (authority.RDATA as DnsSOARecord).Minimum, new DnsNXRecord(authority));
                                        break;

                                    case DnsResponseCode.NoError:
                                        record = new DnsResourceRecord((lastAnswer.RDATA as DnsCNAMERecord).CNAMEDomainName, question.Type, question.Class, (authority.RDATA as DnsSOARecord).Minimum, new DnsEmptyRecord(authority));
                                        break;
                                    }

                                    if (record != null)
                                    {
                                        record.SetExpiry(_minimumRecordTtl, _serveStaleTtl);

                                        CacheRecords(new DnsResourceRecord[] { record });
                                    }

                                    break;
                                }
                            }
                        }
                    }
                }
                else if (authority.Type == DnsResourceRecordType.NS)
                {
                    if (response.Answer.Length == 0)
                    {
                        foreach (DnsQuestionRecord question in response.Question)
                        {
                            foreach (DnsResourceRecord authorityRecord in response.Authority)
                            {
                                if ((authorityRecord.Type == DnsResourceRecordType.NS) && (authorityRecord.RDATA as DnsNSRecord).NSDomainName.Equals(response.Metadata.NameServerAddress.Host, StringComparison.OrdinalIgnoreCase))
                                {
                                    //empty response from authority name server that was queried
                                    DnsResourceRecord record = null;

                                    switch (response.Header.RCODE)
                                    {
                                    case DnsResponseCode.NameError:
                                        record = new DnsResourceRecord(question.Name, question.Type, question.Class, _negativeRecordTtl, new DnsNXRecord(authority));
                                        break;

                                    case DnsResponseCode.NoError:
                                        record = new DnsResourceRecord(question.Name, question.Type, question.Class, _negativeRecordTtl, new DnsEmptyRecord(authority));
                                        break;
                                    }

                                    if (record != null)
                                    {
                                        record.SetExpiry(_minimumRecordTtl, _serveStaleTtl);

                                        CacheRecords(new DnsResourceRecord[] { record });
                                    }

                                    break;
                                }
                            }
                        }
                    }

                    //cache suitable NS records
                    if ((response.Question[0].Type != DnsResourceRecordType.NS) || (response.Answer.Length == 0))
                    {
                        foreach (DnsQuestionRecord question in response.Question)
                        {
                            foreach (DnsResourceRecord authorityRecords in response.Authority)
                            {
                                if ((authorityRecords.Type == DnsResourceRecordType.NS) && (question.Name.Equals(authorityRecords.Name, StringComparison.OrdinalIgnoreCase) || question.Name.EndsWith("." + authorityRecords.Name, StringComparison.OrdinalIgnoreCase)))
                                {
                                    cachableRecords.Add(authorityRecords);

                                    string nsDomain = (authorityRecords.RDATA as DnsNSRecord).NSDomainName;
                                    if (!nsDomain.EndsWith(".root-servers.net", StringComparison.OrdinalIgnoreCase))
                                    {
                                        foreach (DnsResourceRecord record in response.Additional)
                                        {
                                            if (nsDomain.Equals(record.Name, StringComparison.OrdinalIgnoreCase))
                                            {
                                                cachableRecords.Add(record);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                //no authority records
                if (response.Answer.Length == 0)
                {
                    //empty response with no authority
                    foreach (DnsQuestionRecord question in response.Question)
                    {
                        DnsResourceRecord record = null;

                        switch (response.Header.RCODE)
                        {
                        case DnsResponseCode.NameError:
                            record = new DnsResourceRecord(question.Name, question.Type, question.Class, _negativeRecordTtl, new DnsNXRecord(null));
                            break;

                        case DnsResponseCode.NoError:
                            record = new DnsResourceRecord(question.Name, question.Type, question.Class, _negativeRecordTtl, new DnsEmptyRecord(null));
                            break;
                        }

                        if (record != null)
                        {
                            record.SetExpiry(_minimumRecordTtl, _serveStaleTtl);

                            CacheRecords(new DnsResourceRecord[] { record });
                        }
                    }
                }
            }

            //cache for ANY request
            if (response.Header.RCODE == DnsResponseCode.NoError)
            {
                if ((response.Question.Length == 1) && (response.Question[0].Type == DnsResourceRecordType.ANY))
                {
                    DnsResourceRecord record = new DnsResourceRecord(response.Question[0].Name, DnsResourceRecordType.ANY, response.Question[0].Class, _negativeRecordTtl, new DnsANYRecord(response.Answer));
                    record.SetExpiry(_minimumRecordTtl, _serveStaleTtl);

                    CacheRecords(new DnsResourceRecord[] { record });
                }
                else
                {
                    foreach (DnsQuestionRecord question in response.Question)
                    {
                        if (question.Type == DnsResourceRecordType.ANY)
                        {
                            List <DnsResourceRecord> answerRecords = new List <DnsResourceRecord>();

                            foreach (DnsResourceRecord answerRecord in response.Answer)
                            {
                                if (answerRecord.Name.Equals(question.Name, StringComparison.OrdinalIgnoreCase))
                                {
                                    answerRecords.Add(answerRecord);
                                }
                            }

                            DnsResourceRecord record = new DnsResourceRecord(question.Name, DnsResourceRecordType.ANY, question.Class, _negativeRecordTtl, new DnsANYRecord(answerRecords.ToArray()));
                            record.SetExpiry(_minimumRecordTtl, _serveStaleTtl);

                            CacheRecords(new DnsResourceRecord[] { record });
                        }
                    }
                }
            }

            if (cachableRecords.Count < 1)
            {
                return; //nothing to cache
            }
            //set expiry for cached records
            foreach (DnsResourceRecord record in cachableRecords)
            {
                record.SetExpiry(_minimumRecordTtl, _serveStaleTtl);
            }

            CacheRecords(cachableRecords);
        }
Esempio n. 6
0
        protected virtual void CacheRecords(IReadOnlyList <DnsResourceRecord> resourceRecords)
        {
            if (resourceRecords.Count == 1)
            {
                DnsCacheEntry entry = _cache.GetOrAdd(resourceRecords[0].Name.ToLower(), delegate(string key)
                {
                    return(new DnsCacheEntry());
                });

                entry.SetRecords(resourceRecords[0].Type, resourceRecords);
            }
            else
            {
                Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > cacheEntries = DnsResourceRecord.GroupRecords(resourceRecords);

                //add grouped entries into cache
                foreach (KeyValuePair <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > cacheEntry in cacheEntries)
                {
                    DnsCacheEntry entry = _cache.GetOrAdd(cacheEntry.Key.ToLower(), delegate(string key)
                    {
                        return(new DnsCacheEntry());
                    });

                    foreach (KeyValuePair <DnsResourceRecordType, List <DnsResourceRecord> > cacheTypeEntry in cacheEntry.Value)
                    {
                        entry.SetRecords(cacheTypeEntry.Key, cacheTypeEntry.Value);
                    }
                }
            }
        }
Esempio n. 7
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));
        }
Esempio n. 8
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));
        }
Esempio n. 9
0
        public DnsDatagram Query(DnsDatagram request)
        {
            DnsQuestionRecord question = request.Question[0];
            string            domain   = question.Name.ToLower();

            DnsResourceRecord[] records = GetRecords(domain, question.Type);
            if (records != null)
            {
                if (records[0].RDATA is DnsEmptyRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (records[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 (records[0].RDATA is DnsNXRecord)
                {
                    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[] { }, new DnsResourceRecord[] { (records[0].RDATA as DnsNXRecord).Authority }, 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)records.Length, 0, 0), request.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(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));
            }

            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[] { }));
        }
        protected override void CacheRecords(ICollection <DnsResourceRecord> resourceRecords)
        {
            if (resourceRecords.Count == 1)
            {
                foreach (DnsResourceRecord resourceRecord in resourceRecords)
                {
                    CacheEntry(resourceRecord.Name, resourceRecord.Type, new DnsResourceRecord[] { resourceRecord });
                }
            }
            else
            {
                Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > cacheEntries = DnsResourceRecord.GroupRecords(resourceRecords);

                //add grouped entries into cache
                foreach (KeyValuePair <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > cacheEntry in cacheEntries)
                {
                    string domain = cacheEntry.Key;

                    foreach (KeyValuePair <DnsResourceRecordType, List <DnsResourceRecord> > cacheTypeEntry in cacheEntry.Value)
                    {
                        DnsResourceRecordType type    = cacheTypeEntry.Key;
                        DnsResourceRecord[]   records = cacheTypeEntry.Value.ToArray();

                        CacheEntry(domain, type, records);
                    }
                }
            }
        }
Esempio n. 11
0
        public static async Task <DnsDatagram> ReadFromTcpAsync(Stream stream, MemoryStream sharedBuffer, CancellationToken cancellationToken = default)
        {
            DnsDatagram datagram = new DnsDatagram();

            List <DnsQuestionRecord> question   = null;
            List <DnsResourceRecord> answer     = null;
            List <DnsResourceRecord> authority  = null;
            List <DnsResourceRecord> additional = null;

            while (true)
            {
                if (question != null)
                {
                    if (question.Count == 0)
                    {
                        break;
                    }

                    if (question[0].Type != DnsResourceRecordType.AXFR)
                    {
                        break;
                    }

                    if (answer.Count == 0)
                    {
                        break;
                    }

                    DnsResourceRecord lastAnswer = answer[answer.Count - 1];
                    if ((lastAnswer.Type == DnsResourceRecordType.SOA) && lastAnswer.Name.Equals(question[0].Name, StringComparison.OrdinalIgnoreCase))
                    {
                        break; //zone transfer complete
                    }
                }

                ushort length = await ReadUInt16NetworkOrderAsync(stream, cancellationToken);

                sharedBuffer.SetLength(0);
                await stream.CopyToAsync(sharedBuffer, 512, length, cancellationToken);

                datagram._size       += length;
                sharedBuffer.Position = 0;

                if (question == null)
                {
                    datagram._ID = ReadUInt16NetworkOrder(sharedBuffer);
                }
                else
                {
                    ushort ID = ReadUInt16NetworkOrder(sharedBuffer);
                    if (ID != datagram._ID)
                    {
                        throw new DnsClientException("Error while parsing TCP response: response ID does not match with previous response ID.");
                    }
                }

                int lB = sharedBuffer.ReadByte();
                datagram._QR     = Convert.ToByte((lB & 0x80) >> 7);
                datagram._OPCODE = (DnsOpcode)Convert.ToByte((lB & 0x78) >> 3);
                datagram._AA     = Convert.ToByte((lB & 0x4) >> 2);
                datagram._TC     = Convert.ToByte((lB & 0x2) >> 1);
                datagram._RD     = Convert.ToByte(lB & 0x1);

                int rB = sharedBuffer.ReadByte();
                datagram._RA    = Convert.ToByte((rB & 0x80) >> 7);
                datagram._Z     = Convert.ToByte((rB & 0x40) >> 6);
                datagram._AD    = Convert.ToByte((rB & 0x20) >> 5);
                datagram._CD    = Convert.ToByte((rB & 0x10) >> 4);
                datagram._RCODE = (DnsResponseCode)(rB & 0xf);

                ushort QDCOUNT = ReadUInt16NetworkOrder(sharedBuffer);
                ushort ANCOUNT = ReadUInt16NetworkOrder(sharedBuffer);
                ushort NSCOUNT = ReadUInt16NetworkOrder(sharedBuffer);
                ushort ARCOUNT = ReadUInt16NetworkOrder(sharedBuffer);

                if (question == null)
                {
                    question = new List <DnsQuestionRecord>(QDCOUNT);
                }

                if (answer == null)
                {
                    answer = new List <DnsResourceRecord>(ANCOUNT);
                }

                if (authority == null)
                {
                    authority = new List <DnsResourceRecord>(NSCOUNT);
                }

                if (additional == null)
                {
                    additional = new List <DnsResourceRecord>(ARCOUNT);
                }

                try
                {
                    for (int i = 0; i < QDCOUNT; i++)
                    {
                        question.Add(new DnsQuestionRecord(sharedBuffer));
                    }

                    for (int i = 0; i < ANCOUNT; i++)
                    {
                        answer.Add(new DnsResourceRecord(sharedBuffer));
                    }

                    for (int i = 0; i < NSCOUNT; i++)
                    {
                        authority.Add(new DnsResourceRecord(sharedBuffer));
                    }

                    for (int i = 0; i < ARCOUNT; i++)
                    {
                        additional.Add(new DnsResourceRecord(sharedBuffer));
                    }
                }
                catch (Exception ex)
                {
                    datagram._parsingException = ex;
                    break;
                }
            }

            datagram._question   = question;
            datagram._answer     = answer;
            datagram._authority  = authority;
            datagram._additional = additional;

            return(datagram);
        }
Esempio n. 12
0
            public void SetRecords(DnsResourceRecordType type, IReadOnlyList <DnsResourceRecord> records)
            {
                if ((records.Count > 0) && (records[0].RDATA is DnsSpecialCacheRecord splRecord) && splRecord.IsFailure)
                {
                    //call trying to cache failure record
                    if (_entries.TryGetValue(type, out IReadOnlyList <DnsResourceRecord> existingRecords))
                    {
                        if ((existingRecords.Count > 0) && !(existingRecords[0].RDATA is DnsSpecialCacheRecord existingSplRecord && existingSplRecord.IsFailure) && !DnsResourceRecord.IsRRSetStale(existingRecords))
                        {
                            return; //skip to avoid overwriting a useful record with a failure record
                        }
                    }
                }

                _entries[type] = records;
            }
Esempio n. 13
0
        public void CacheResponse(DnsDatagram response)
        {
            if (!response.IsResponse || response.Truncation || (response.Question.Count == 0))
            {
                return; //ineligible response
            }
            switch (response.RCODE)
            {
            case DnsResponseCode.NoError:
            case DnsResponseCode.NxDomain:
            case DnsResponseCode.YXDomain:
                //cache response after this switch
                break;

            default:
                //cache as failure record
                foreach (DnsQuestionRecord question in response.Question)
                {
                    DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, question.Class, _failureRecordTtl, new DnsSpecialCacheRecord(response, true));
                    record.SetExpiry(_minimumRecordTtl, _maximumRecordTtl, _serveStaleTtl);

                    InternalCacheRecords(new DnsResourceRecord[] { record });
                }

                return;
            }

            //combine all records in the response
            List <DnsResourceRecord> cachableRecords = new List <DnsResourceRecord>();

            //get cachable answer records
            foreach (DnsQuestionRecord question in response.Question)
            {
                string qName = question.Name;

                foreach (DnsResourceRecord answer in response.Answer)
                {
                    if (answer.Name.Equals(qName, StringComparison.OrdinalIgnoreCase))
                    {
                        cachableRecords.Add(answer);

                        switch (answer.Type)
                        {
                        case DnsResourceRecordType.CNAME:
                            qName = (answer.RDATA as DnsCNAMERecord).Domain;
                            break;

                        case DnsResourceRecordType.NS:
                            if (response.Authority.Count == 0)
                            {
                                //add glue from additional section
                                string nsDomain = (answer.RDATA as DnsNSRecord).NameServer;

                                foreach (DnsResourceRecord additional in response.Additional)
                                {
                                    if (nsDomain.Equals(additional.Name, StringComparison.OrdinalIgnoreCase))
                                    {
                                        switch (additional.Type)
                                        {
                                        case DnsResourceRecordType.A:
                                            if (IPAddress.IsLoopback((additional.RDATA as DnsARecord).Address))
                                            {
                                                continue;
                                            }

                                            break;

                                        case DnsResourceRecordType.AAAA:
                                            if (IPAddress.IsLoopback((additional.RDATA as DnsAAAARecord).Address))
                                            {
                                                continue;
                                            }

                                            break;
                                        }

                                        AddGlueRecordTo(answer, additional);
                                    }
                                }
                            }
                            break;

                        case DnsResourceRecordType.MX:
                            if (response.Authority.Count == 0)
                            {
                                //add glue from additional section
                                string mxExchange = (answer.RDATA as DnsMXRecord).Exchange;

                                foreach (DnsResourceRecord additional in response.Additional)
                                {
                                    if (mxExchange.Equals(additional.Name, StringComparison.OrdinalIgnoreCase))
                                    {
                                        AddGlueRecordTo(answer, additional);
                                    }
                                }
                            }
                            break;

                        case DnsResourceRecordType.SRV:
                            if (response.Authority.Count == 0)
                            {
                                //add glue from additional section
                                string srvTarget = (answer.RDATA as DnsSRVRecord).Target;

                                foreach (DnsResourceRecord additional in response.Additional)
                                {
                                    if (srvTarget.Equals(additional.Name, StringComparison.OrdinalIgnoreCase))
                                    {
                                        AddGlueRecordTo(answer, additional);
                                    }
                                }
                            }
                            break;
                        }
                    }
                    else if ((answer.Type == DnsResourceRecordType.DNAME) && qName.EndsWith("." + answer.Name, StringComparison.OrdinalIgnoreCase))
                    {
                        cachableRecords.Add(answer);
                    }
                }
            }

            //get cachable authority records
            if (response.Authority.Count > 0)
            {
                foreach (DnsResourceRecord authority in response.Authority)
                {
                    authority.SetExpiry(_minimumRecordTtl, _maximumRecordTtl, _serveStaleTtl);
                }

                DnsResourceRecord firstAuthority = response.Authority[0];
                if (firstAuthority.Type == DnsResourceRecordType.SOA)
                {
                    if (response.Answer.Count == 0)
                    {
                        //empty response with authority
                        foreach (DnsQuestionRecord question in response.Question)
                        {
                            DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, question.Class, (firstAuthority.RDATA as DnsSOARecord).Minimum, new DnsSpecialCacheRecord(response));
                            record.SetExpiry(_minimumRecordTtl, _maximumRecordTtl, _serveStaleTtl);

                            InternalCacheRecords(new DnsResourceRecord[] { record });
                        }
                    }
                    else
                    {
                        //answer response with authority
                        DnsResourceRecord lastAnswer = response.Answer[response.Answer.Count - 1];
                        if (lastAnswer.Type == DnsResourceRecordType.CNAME)
                        {
                            if ((response.RCODE != DnsResponseCode.NxDomain) || (response.Answer.Count == 1))
                            {
                                //negative cache only when RCODE is not NXDOMAIN or when RCODE is NXDOMAIN and there is only 1 CNAME in answer
                                foreach (DnsQuestionRecord question in response.Question)
                                {
                                    DnsResourceRecord record = new DnsResourceRecord((lastAnswer.RDATA as DnsCNAMERecord).Domain, question.Type, question.Class, (firstAuthority.RDATA as DnsSOARecord).Minimum, new DnsSpecialCacheRecord(response));
                                    record.SetExpiry(_minimumRecordTtl, _maximumRecordTtl, _serveStaleTtl);

                                    InternalCacheRecords(new DnsResourceRecord[] { record });
                                }
                            }
                        }
                    }
                }
                else if (firstAuthority.Type == DnsResourceRecordType.NS)
                {
                    if (response.Answer.Count == 0)
                    {
                        //response is probably referral response
                        bool isReferralResponse = true;

                        foreach (DnsQuestionRecord question in response.Question)
                        {
                            foreach (DnsResourceRecord authority in response.Authority)
                            {
                                if ((authority.Type == DnsResourceRecordType.NS) && (authority.RDATA as DnsNSRecord).NameServer.Equals(response.Metadata.NameServerAddress.Host, StringComparison.OrdinalIgnoreCase))
                                {
                                    //empty response from authority name server that was queried
                                    DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, question.Class, _negativeRecordTtl, new DnsSpecialCacheRecord(response));
                                    record.SetExpiry(_minimumRecordTtl, _maximumRecordTtl, _serveStaleTtl);

                                    InternalCacheRecords(new DnsResourceRecord[] { record });
                                    isReferralResponse = false;
                                    break;
                                }
                            }
                        }

                        if (isReferralResponse)
                        {
                            //cache and glue suitable NS records
                            foreach (DnsResourceRecord authority in response.Authority)
                            {
                                if (authority.Type != DnsResourceRecordType.NS)
                                {
                                    continue;
                                }

                                cachableRecords.Add(authority);

                                //add glue from additional section
                                string nsDomain = (authority.RDATA as DnsNSRecord).NameServer;

                                foreach (DnsResourceRecord additional in response.Additional)
                                {
                                    if (nsDomain.Equals(additional.Name, StringComparison.OrdinalIgnoreCase))
                                    {
                                        switch (additional.Type)
                                        {
                                        case DnsResourceRecordType.A:
                                            if (IPAddress.IsLoopback((additional.RDATA as DnsARecord).Address))
                                            {
                                                continue;
                                            }

                                            break;

                                        case DnsResourceRecordType.AAAA:
                                            if (IPAddress.IsLoopback((additional.RDATA as DnsAAAARecord).Address))
                                            {
                                                continue;
                                            }

                                            break;
                                        }

                                        AddGlueRecordTo(authority, additional);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                //no authority records
                if (response.Answer.Count == 0)
                {
                    //empty response with no authority
                    foreach (DnsQuestionRecord question in response.Question)
                    {
                        DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, question.Class, _negativeRecordTtl, new DnsSpecialCacheRecord(response));
                        record.SetExpiry(_minimumRecordTtl, _maximumRecordTtl, _serveStaleTtl);

                        InternalCacheRecords(new DnsResourceRecord[] { record });
                    }
                }
            }

            if (cachableRecords.Count < 1)
            {
                return; //nothing to cache
            }
            //set expiry for cached records
            foreach (DnsResourceRecord record in cachableRecords)
            {
                record.SetExpiry(_minimumRecordTtl, _maximumRecordTtl, _serveStaleTtl);

                foreach (DnsResourceRecord glueRecord in GetGlueRecordsFrom(record))
                {
                    glueRecord.SetExpiry(_minimumRecordTtl, _maximumRecordTtl, _serveStaleTtl);
                }
            }

            InternalCacheRecords(cachableRecords);
        }
Esempio n. 14
0
        public void CacheResponse(DnsDatagram response)
        {
            if (!response.Header.IsResponse)
            {
                return;
            }

            //combine all records in the response
            List <DnsResourceRecord> allRecords = new List <DnsResourceRecord>();

            switch (response.Header.RCODE)
            {
            case DnsResponseCode.NameError:
                if (response.Authority.Length > 0)
                {
                    DnsResourceRecord authority = response.Authority[0];
                    if (authority.Type == DnsResourceRecordType.SOA)
                    {
                        authority.SetExpiry(MINIMUM_RECORD_TTL, 0u);

                        foreach (DnsQuestionRecord question in response.Question)
                        {
                            DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, DnsClass.IN, DEFAULT_RECORD_TTL, new DnsNXRecord(authority));
                            record.SetExpiry(MINIMUM_RECORD_TTL, 0u);

                            CacheEntry(question.Name, question.Type, new DnsResourceRecord[] { record });
                        }
                    }
                }
                break;

            case DnsResponseCode.NoError:
                if (response.Answer.Length > 0)
                {
                    foreach (DnsQuestionRecord question in response.Question)
                    {
                        string qName = question.Name;

                        foreach (DnsResourceRecord answer in response.Answer)
                        {
                            if (answer.Name.Equals(qName, StringComparison.CurrentCultureIgnoreCase))
                            {
                                allRecords.Add(answer);

                                switch (answer.Type)
                                {
                                case DnsResourceRecordType.CNAME:
                                    qName = (answer.RDATA as DnsCNAMERecord).CNAMEDomainName;
                                    break;

                                case DnsResourceRecordType.NS:
                                    string nsDomain = (answer.RDATA as DnsNSRecord).NSDomainName;

                                    if (!nsDomain.EndsWith(".root-servers.net", StringComparison.CurrentCultureIgnoreCase))
                                    {
                                        foreach (DnsResourceRecord record in response.Additional)
                                        {
                                            if (nsDomain.Equals(record.Name, StringComparison.CurrentCultureIgnoreCase))
                                            {
                                                allRecords.Add(record);
                                            }
                                        }
                                    }

                                    break;

                                case DnsResourceRecordType.MX:
                                    string mxExchange = (answer.RDATA as DnsMXRecord).Exchange;

                                    foreach (DnsResourceRecord record in response.Additional)
                                    {
                                        if (mxExchange.Equals(record.Name, StringComparison.CurrentCultureIgnoreCase))
                                        {
                                            allRecords.Add(record);
                                        }
                                    }

                                    break;
                                }
                            }
                        }
                    }
                }
                else if (response.Authority.Length > 0)
                {
                    DnsResourceRecord authority = response.Authority[0];
                    if (authority.Type == DnsResourceRecordType.SOA)
                    {
                        authority.SetExpiry(MINIMUM_RECORD_TTL, 0u);

                        //empty response with authority
                        foreach (DnsQuestionRecord question in response.Question)
                        {
                            DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, DnsClass.IN, DEFAULT_RECORD_TTL, new DnsEmptyRecord(authority));
                            record.SetExpiry(MINIMUM_RECORD_TTL, 0u);

                            CacheEntry(question.Name, question.Type, new DnsResourceRecord[] { record });
                        }
                    }
                    else
                    {
                        foreach (DnsQuestionRecord question in response.Question)
                        {
                            foreach (DnsResourceRecord authorityRecord in response.Authority)
                            {
                                if ((authorityRecord.Type == DnsResourceRecordType.NS) && question.Name.Equals(authorityRecord.Name, StringComparison.CurrentCultureIgnoreCase) && (authorityRecord.RDATA as DnsNSRecord).NSDomainName.Equals(response.Metadata.NameServerAddress.Host, StringComparison.CurrentCultureIgnoreCase))
                                {
                                    //empty response from authority name server
                                    DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, DnsClass.IN, DEFAULT_RECORD_TTL, new DnsEmptyRecord(null));
                                    record.SetExpiry(MINIMUM_RECORD_TTL, 0u);

                                    CacheEntry(question.Name, question.Type, new DnsResourceRecord[] { record });
                                    break;
                                }
                            }
                        }
                    }
                }
                else
                {
                    //empty response with no authority
                    foreach (DnsQuestionRecord question in response.Question)
                    {
                        DnsResourceRecord record = new DnsResourceRecord(question.Name, question.Type, DnsClass.IN, DEFAULT_RECORD_TTL, new DnsEmptyRecord(null));
                        record.SetExpiry(MINIMUM_RECORD_TTL, 0u);

                        CacheEntry(question.Name, question.Type, new DnsResourceRecord[] { record });
                    }
                }

                break;

            default:
                return;     //nothing to do
            }

            if ((response.Question.Length > 0) && (response.Question[0].Type != DnsResourceRecordType.NS))
            {
                foreach (DnsQuestionRecord question in response.Question)
                {
                    foreach (DnsResourceRecord authority in response.Authority)
                    {
                        if (question.Name.Equals(authority.Name, StringComparison.CurrentCultureIgnoreCase) || question.Name.EndsWith("." + authority.Name, StringComparison.CurrentCultureIgnoreCase))
                        {
                            allRecords.Add(authority);

                            if (authority.Type == DnsResourceRecordType.NS)
                            {
                                string nsDomain = (authority.RDATA as DnsNSRecord).NSDomainName;

                                if (!nsDomain.EndsWith(".root-servers.net", StringComparison.CurrentCultureIgnoreCase))
                                {
                                    foreach (DnsResourceRecord record in response.Additional)
                                    {
                                        if (nsDomain.Equals(record.Name, StringComparison.CurrentCultureIgnoreCase))
                                        {
                                            allRecords.Add(record);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            //set expiry for cached records
            foreach (DnsResourceRecord record in allRecords)
            {
                record.SetExpiry(MINIMUM_RECORD_TTL, 0u);
            }

            #region group all records by domain and type

            Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > cacheEntries = new Dictionary <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > >();

            foreach (DnsResourceRecord record in allRecords)
            {
                Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > cacheTypeEntries;

                if (cacheEntries.ContainsKey(record.Name))
                {
                    cacheTypeEntries = cacheEntries[record.Name];
                }
                else
                {
                    cacheTypeEntries = new Dictionary <DnsResourceRecordType, List <DnsResourceRecord> >();
                    cacheEntries.Add(record.Name, cacheTypeEntries);
                }

                List <DnsResourceRecord> cacheRREntries;

                if (cacheTypeEntries.ContainsKey(record.Type))
                {
                    cacheRREntries = cacheTypeEntries[record.Type];
                }
                else
                {
                    cacheRREntries = new List <DnsResourceRecord>();
                    cacheTypeEntries.Add(record.Type, cacheRREntries);
                }

                cacheRREntries.Add(record);
            }

            #endregion

            //add grouped entries into cache
            foreach (KeyValuePair <string, Dictionary <DnsResourceRecordType, List <DnsResourceRecord> > > cacheEntry in cacheEntries)
            {
                string domain = cacheEntry.Key;

                foreach (KeyValuePair <DnsResourceRecordType, List <DnsResourceRecord> > cacheTypeEntry in cacheEntry.Value)
                {
                    DnsResourceRecordType type    = cacheTypeEntry.Key;
                    DnsResourceRecord[]   records = cacheTypeEntry.Value.ToArray();

                    CacheEntry(domain, type, records);
                }
            }

            //cache for ANY request
            if (response.Question[0].Type == DnsResourceRecordType.ANY)
            {
                CacheEntry(response.Question[0].Name, DnsResourceRecordType.ANY, response.Answer);
            }
        }
Esempio n. 15
0
 public DnsNXRecord(DnsResourceRecord authority)
 {
     _authority = authority;
 }
Esempio n. 16
0
 public DnsEmptyRecord(DnsResourceRecord authority)
 {
     _authority = authority;
 }
        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[] { }));
        }