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