Example #1
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);
        }
Example #2
0
 public DnsEmptyRecord(DnsResourceRecord authority)
 {
     _authority = authority;
 }
Example #3
0
        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[] { }));
            }

            DnsResourceRecord[] nameServers = GetClosestNameServers(question.Name);
            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) && (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);
                    }
                }

                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[] { }));
        }
Example #4
0
 public DnsNXRecord(DnsResourceRecord authority)
 {
     _authority = authority;
 }
Example #5
0
        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);
                    }
                }
            }
        }