public void WriteTo(Stream s, List <DnsDomainOffset> domainEntries) { long originalPosition = s.Position; //write dummy RDLENGTH s.Write(new byte[] { 0, 0 }, 0, 2); //write RDATA WriteRecordData(s, domainEntries); long finalPosition = s.Position; //write actual RDLENGTH ushort length = Convert.ToUInt16(finalPosition - originalPosition - 2); s.Position = originalPosition; DnsDatagram.WriteUInt16NetworkOrder(length, s); s.Position = finalPosition; }
protected override void WriteRecordData(Stream s, List <DnsDomainOffset> domainEntries) { DnsDatagram.SerializeDomainName(_nsDomainName, s, domainEntries); }
protected override void Parse(Stream s) { _nsDomainName = DnsDatagram.DeserializeDomainName(s); }
public static NameServerAddress[] GetNameServersFromResponse(DnsDatagram response, bool preferIPv6) { List <NameServerAddress> nameServers = new List <NameServerAddress>(response.Authority.Length); DnsResourceRecord[] authorityRecords; if ((response.Question.Length > 0) && (response.Question[0].Type == DnsResourceRecordType.NS) && (response.Answer.Length > 0)) { authorityRecords = response.Answer; } else { authorityRecords = response.Authority; } foreach (DnsResourceRecord authorityRecord in authorityRecords) { if (authorityRecord.Type == DnsResourceRecordType.NS) { DnsNSRecord nsRecord = (DnsNSRecord)authorityRecord.RDATA; IPEndPoint endPoint = null; //find ip address of authoritative name server from additional records foreach (DnsResourceRecord rr in response.Additional) { if (nsRecord.NSDomainName.Equals(rr.Name, StringComparison.OrdinalIgnoreCase)) { switch (rr.Type) { case DnsResourceRecordType.A: endPoint = new IPEndPoint(((DnsARecord)rr.RDATA).Address, 53); nameServers.Add(new NameServerAddress(nsRecord.NSDomainName, endPoint)); break; case DnsResourceRecordType.AAAA: endPoint = new IPEndPoint(((DnsAAAARecord)rr.RDATA).Address, 53); if (preferIPv6) { nameServers.Add(new NameServerAddress(nsRecord.NSDomainName, endPoint)); } break; } } } if (endPoint == null) { nameServers.Add(new NameServerAddress(new DomainEndPoint(nsRecord.NSDomainName, 53))); } } } NameServerAddress[] nsArray = nameServers.ToArray(); DnsClient.ShuffleArray(nsArray); if (preferIPv6) { Array.Sort(nsArray); } return(nsArray); }
public void RecursiveResolveIPAddress(DnsCache cache = null, NetProxy proxy = null, bool preferIPv6 = false, DnsTransportProtocol protocol = DnsTransportProtocol.Udp, int retries = 2, int timeout = 2000, DnsTransportProtocol recursiveResolveProtocol = DnsTransportProtocol.Udp) { lock (_ipEndPointResolverLock) { if (_ipEndPointExpires && (DateTime.UtcNow < _ipEndPointExpiresOn)) { return; } string domain; if (_dohEndPoint != null) { domain = _dohEndPoint.Host; } else if (_domainEndPoint != null) { domain = _domainEndPoint.Address; } else { return; } if (domain == "localhost") { _ipEndPoint = new IPEndPoint((preferIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback), this.Port); return; } if (IPAddress.TryParse(domain, out IPAddress address)) { _ipEndPoint = new IPEndPoint(address, this.Port); return; } IPEndPoint ipEndPoint = null; DateTime ipEndPointExpiresOn = DateTime.MinValue; if (preferIPv6) { DnsDatagram nsResponse = DnsClient.RecursiveResolve(new DnsQuestionRecord(domain, DnsResourceRecordType.AAAA, DnsClass.IN), null, cache, proxy, true, protocol, retries, timeout, recursiveResolveProtocol); if ((nsResponse.Header.RCODE == DnsResponseCode.NoError) && (nsResponse.Answer.Length > 0) && (nsResponse.Answer[0].Type == DnsResourceRecordType.AAAA)) { ipEndPoint = new IPEndPoint((nsResponse.Answer[0].RDATA as DnsAAAARecord).Address, this.Port); ipEndPointExpiresOn = DateTime.UtcNow.AddSeconds(nsResponse.Answer[0].TtlValue); } } if (ipEndPoint == null) { DnsDatagram nsResponse = DnsClient.RecursiveResolve(new DnsQuestionRecord(domain, DnsResourceRecordType.A, DnsClass.IN), null, cache, proxy, false, protocol, retries, timeout, recursiveResolveProtocol); if ((nsResponse.Header.RCODE == DnsResponseCode.NoError) && (nsResponse.Answer.Length > 0) && (nsResponse.Answer[0].Type == DnsResourceRecordType.A)) { ipEndPoint = new IPEndPoint((nsResponse.Answer[0].RDATA as DnsARecord).Address, this.Port); ipEndPointExpiresOn = DateTime.UtcNow.AddSeconds(nsResponse.Answer[0].TtlValue); } } if (ipEndPoint == null) { throw new DnsClientException("No IP address was found for name server: " + domain); } _ipEndPoint = ipEndPoint; _ipEndPointExpires = true; _ipEndPointExpiresOn = ipEndPointExpiresOn; } }
public void WriteTo(Stream s, List <DnsDomainOffset> domainEntries) { DnsDatagram.SerializeDomainName(_name, s, domainEntries); DnsDatagram.WriteUInt16NetworkOrder((ushort)_type, s); DnsDatagram.WriteUInt16NetworkOrder((ushort)_class, s); }
public DnsQuestionRecord(Stream s) { _name = DnsDatagram.DeserializeDomainName(s); _type = (DnsResourceRecordType)DnsDatagram.ReadUInt16NetworkOrder(s); _class = (DnsClass)DnsDatagram.ReadUInt16NetworkOrder(s); }
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 abstract DnsDatagram Query(DnsDatagram request);
protected override void WriteRecordData(Stream s, List <DnsDomainOffset> domainEntries) { DnsDatagram.WriteUInt16NetworkOrder(_preference, s); DnsDatagram.SerializeDomainName(_exchange, s, domainEntries); }
protected override void Parse(Stream s) { _preference = DnsDatagram.ReadUInt16NetworkOrder(s); _exchange = DnsDatagram.DeserializeDomainName(s); }
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[] { })); }