public static List <NameServerAddress> GetNameServersFromResponse(DnsDatagram response, bool preferIPv6, bool selectOnlyNameServersWithGlue) { List <NameServerAddress> nameServers = new List <NameServerAddress>(response.Authority.Count); foreach (DnsResourceRecord authorityRecord in response.Authority) { 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.NameServer.Equals(rr.Name, StringComparison.OrdinalIgnoreCase)) { switch (rr.Type) { case DnsResourceRecordType.A: endPoint = new IPEndPoint(((DnsARecord)rr.RDATA).Address, 53); nameServers.Add(new NameServerAddress(nsRecord.NameServer, endPoint)); break; case DnsResourceRecordType.AAAA: endPoint = new IPEndPoint(((DnsAAAARecord)rr.RDATA).Address, 53); if (preferIPv6) { nameServers.Add(new NameServerAddress(nsRecord.NameServer, endPoint)); } break; } } } if ((endPoint == null) && !selectOnlyNameServersWithGlue) { nameServers.Add(new NameServerAddress(new DomainEndPoint(nsRecord.NameServer, 53))); } } } return(nameServers); }
internal DnsDatagram Clone(IReadOnlyList <DnsResourceRecord> answer, IReadOnlyList <DnsResourceRecord> authority) { if (answer == null) { answer = _answer; } if (authority == null) { authority = _authority; } DnsDatagram datagram = new DnsDatagram(_ID, _QR == 1, _OPCODE, _AA == 1, _TC == 1, _RD == 1, _RA == 1, _AD == 1, _CD == 1, _RCODE, _question, answer, authority, _additional); datagram._metadata = _metadata; return(datagram); }
public void WriteTo(Stream s, List <DnsDomainOffset> domainEntries) { long originalPosition = s.Position; //write dummy RDLENGTH s.Position += 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; }
public string ResolvePTR(IPAddress ip) { DnsDatagram response = Resolve(new DnsQuestionRecord(ip, DnsClass.IN)); switch (response.Header.RCODE) { case DnsResponseCode.NoError: if ((response.Header.ANCOUNT > 0) && (response.Answer[0].Type == DnsResourceRecordType.PTR)) { return(((DnsPTRRecord)response.Answer[0].RDATA).PTRDomainName); } return(null); case DnsResponseCode.NameError: throw new NameErrorDnsClientException("PTR record does not exists for ip: " + ip.ToString() + "; Name server: " + response.NameServerAddress.ToString()); default: throw new DnsClientException("Name server returned error. DNS RCODE: " + response.Header.RCODE.ToString() + " (" + response.Header.RCODE + ")"); } }
public DnsQuestionRecord(Stream s) { _name = DnsDatagram.ConvertLabelToDomain(s); _type = (DnsResourceRecordType)DnsDatagram.ReadUInt16NetworkOrder(s); _class = (DnsClass)DnsDatagram.ReadUInt16NetworkOrder(s); }
protected override void Parse(Stream s) { _ptrDomainName = DnsDatagram.DeserializeDomainName(s); }
public DnsQuestionRecord(Stream s) { _name = DnsDatagram.DeserializeDomainName(s); _type = (DnsResourceRecordType)DnsDatagram.ReadUInt16NetworkOrder(s); _class = (DnsClass)DnsDatagram.ReadUInt16NetworkOrder(s); }
public IPAddress[] ResolveIP(string domain, bool preferIPv6 = false) { int hopCount = 0; DnsResourceRecordType type = preferIPv6 ? DnsResourceRecordType.AAAA : DnsResourceRecordType.A; while ((hopCount++) < MAX_HOPS) { DnsDatagram response = Resolve(new DnsQuestionRecord(domain, type, DnsClass.IN)); switch (response.Header.RCODE) { case DnsResponseCode.NoError: if (response.Header.ANCOUNT == 0) { if (type == DnsResourceRecordType.AAAA) { type = DnsResourceRecordType.A; continue; } return(new IPAddress[] { }); } List <IPAddress> ipAddresses = new List <IPAddress>(); foreach (DnsResourceRecord record in response.Answer) { if (record.Name.Equals(domain, StringComparison.CurrentCultureIgnoreCase)) { switch (record.Type) { case DnsResourceRecordType.A: ipAddresses.Add(((DnsARecord)record.RDATA).Address); break; case DnsResourceRecordType.AAAA: ipAddresses.Add(((DnsAAAARecord)record.RDATA).Address); break; case DnsResourceRecordType.CNAME: domain = ((DnsCNAMERecord)record.RDATA).CNAMEDomainName; break; default: throw new DnsClientException("Name server [" + response.NameServerAddress.ToString() + "] returned unexpected record type [ " + record.Type.ToString() + "] for domain: " + domain); } } } if (ipAddresses.Count > 0) { return(ipAddresses.ToArray()); } break; case DnsResponseCode.NameError: throw new NameErrorDnsClientException("Domain does not exists: " + domain + "; Name server: " + response.NameServerAddress.ToString()); default: throw new DnsClientException("Name server returned error. DNS RCODE: " + response.Header.RCODE.ToString() + " (" + response.Header.RCODE + ")"); } } throw new DnsClientException("No answer received from name server for domain: " + domain); }
public string[] ResolveMX(string domain, bool resolveIP = false, bool preferIPv6 = false) { if (IPAddress.TryParse(domain, out IPAddress parsedIP)) { //host is valid ip address return(new string[] { domain }); } int hopCount = 0; while ((hopCount++) < MAX_HOPS) { DnsDatagram response = Resolve(new DnsQuestionRecord(domain, DnsResourceRecordType.MX, DnsClass.IN)); switch (response.Header.RCODE) { case DnsResponseCode.NoError: if (response.Header.ANCOUNT == 0) { return new string[] { } } ; List <DnsMXRecord> mxRecordsList = new List <DnsMXRecord>(); foreach (DnsResourceRecord record in response.Answer) { if (record.Name.Equals(domain, StringComparison.CurrentCultureIgnoreCase)) { switch (record.Type) { case DnsResourceRecordType.MX: mxRecordsList.Add((DnsMXRecord)record.RDATA); break; case DnsResourceRecordType.CNAME: domain = ((DnsCNAMERecord)record.RDATA).CNAMEDomainName; break; default: throw new DnsClientException("Name server [" + response.NameServerAddress.ToString() + "] returned unexpected record type [" + record.Type.ToString() + "] for domain: " + domain); } } } if (mxRecordsList.Count > 0) { DnsMXRecord[] mxRecords = mxRecordsList.ToArray(); //sort by mx preference Array.Sort(mxRecords); if (resolveIP) { List <string> mxEntries = new List <string>(); //check glue records for (int i = 0; i < mxRecords.Length; i++) { string mxDomain = mxRecords[i].Exchange; bool glueRecordFound = false; foreach (DnsResourceRecord record in response.Additional) { if (record.Name.Equals(mxDomain, StringComparison.CurrentCultureIgnoreCase)) { switch (record.Type) { case DnsResourceRecordType.A: if (!preferIPv6) { mxEntries.Add(((DnsARecord)record.RDATA).Address.ToString()); glueRecordFound = true; } break; case DnsResourceRecordType.AAAA: if (preferIPv6) { mxEntries.Add(((DnsAAAARecord)record.RDATA).Address.ToString()); glueRecordFound = true; } break; } } } if (!glueRecordFound) { try { IPAddress[] ipList = ResolveIP(mxDomain, preferIPv6); foreach (IPAddress ip in ipList) { mxEntries.Add(ip.ToString()); } } catch (NameErrorDnsClientException) { } catch (DnsClientException) { mxEntries.Add(mxDomain); } } } return(mxEntries.ToArray()); } else { string[] mxEntries = new string[mxRecords.Length]; for (int i = 0; i < mxRecords.Length; i++) { mxEntries[i] = mxRecords[i].Exchange; } return(mxEntries); } } break; case DnsResponseCode.NameError: throw new NameErrorDnsClientException("Domain does not exists: " + domain + "; Name server: " + response.NameServerAddress.ToString()); default: throw new DnsClientException("Name server returned error. DNS RCODE: " + response.Header.RCODE.ToString() + " (" + response.Header.RCODE + ")"); } } throw new DnsClientException("No answer received from name server for domain: " + domain); }
public static DnsDatagram ResolveViaNameServers(DnsQuestionRecord question, NameServerAddress[] nameServers = null, IDnsCache cache = null, NetProxy proxy = null, bool preferIPv6 = false, bool tcp = false, int retries = 2, int maxStackCount = 10) { if ((nameServers != null) && (nameServers.Length > 0)) { //create copy of name servers array so that the values in original array are not messed due to shuffling feature NameServerAddress[] nameServersCopy = new NameServerAddress[nameServers.Length]; Array.Copy(nameServers, nameServersCopy, nameServers.Length); nameServers = nameServersCopy; } Stack <ResolverData> resolverStack = new Stack <ResolverData>(); int stackNameServerIndex = 0; while (true) //stack loop { if (resolverStack.Count > maxStackCount) { while (resolverStack.Count > 0) { ResolverData data = resolverStack.Pop(); question = data.Question; } throw new DnsClientException("DnsClient exceeded the maximum stack count to resolve the domain: " + question.Name); } if (cache != null) { DnsDatagram request = new DnsDatagram(new DnsHeader(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, 1, 0, 0, 0), new DnsQuestionRecord[] { question }, null, null, null); DnsDatagram cacheResponse = cache.Query(request); switch (cacheResponse.Header.RCODE) { case DnsResponseCode.NoError: if (cacheResponse.Answer.Length > 0) { if (resolverStack.Count == 0) { return(cacheResponse); } else { ResolverData data = resolverStack.Pop(); question = data.Question; nameServers = data.NameServers; stackNameServerIndex = data.NameServerIndex; switch (cacheResponse.Answer[0].Type) { case DnsResourceRecordType.AAAA: nameServers[stackNameServerIndex] = new NameServerAddress(nameServers[stackNameServerIndex].Domain, (cacheResponse.Answer[0].RDATA as DnsAAAARecord).Address); break; case DnsResourceRecordType.A: nameServers[stackNameServerIndex] = new NameServerAddress(nameServers[stackNameServerIndex].Domain, (cacheResponse.Answer[0].RDATA as DnsARecord).Address); break; default: //didnt find IP for current name server stackNameServerIndex++; //increment to skip current name server break; } continue; //stack loop } } if (cacheResponse.Authority.Length > 0) { if (cacheResponse.Authority[0].Type == DnsResourceRecordType.SOA) { if (resolverStack.Count == 0) { return(cacheResponse); } else { if (question.Type == DnsResourceRecordType.AAAA) { question = new DnsQuestionRecord(question.Name, DnsResourceRecordType.A, question.Class); } else { //didnt find IP for current name server //pop and try next name server ResolverData data = resolverStack.Pop(); question = data.Question; nameServers = data.NameServers; stackNameServerIndex = data.NameServerIndex + 1; //increment to skip current name server } continue; //to stack loop } } if ((nameServers == null) || (nameServers.Length == 0)) { NameServerAddress[] cacheNameServers = NameServerAddress.GetNameServersFromResponse(cacheResponse, preferIPv6, true); if (cacheNameServers.Length > 0) { nameServers = cacheNameServers; } } } break; case DnsResponseCode.NameError: if (resolverStack.Count == 0) { return(cacheResponse); } else { //current name server domain doesnt exists //pop and try next name server ResolverData data = resolverStack.Pop(); question = data.Question; nameServers = data.NameServers; stackNameServerIndex = data.NameServerIndex + 1; //increment to skip current name server continue; //stack loop } } } if ((nameServers == null) || (nameServers.Length == 0)) { //create copy of root name servers array so that the values in original array are not messed due to shuffling feature if (preferIPv6) { nameServers = new NameServerAddress[ROOT_NAME_SERVERS_IPv6.Length]; Array.Copy(ROOT_NAME_SERVERS_IPv6, nameServers, ROOT_NAME_SERVERS_IPv6.Length); } else { nameServers = new NameServerAddress[ROOT_NAME_SERVERS_IPv4.Length]; Array.Copy(ROOT_NAME_SERVERS_IPv4, nameServers, ROOT_NAME_SERVERS_IPv4.Length); } } NameServerAddress.Shuffle(nameServers); int hopCount = 0; while ((hopCount++) < MAX_HOPS) //resolver loop { //copy and reset stack name server index since its one time use only after stack pop int i = stackNameServerIndex; stackNameServerIndex = 0; //query name servers one by one for (; i < nameServers.Length; i++) //retry next server loop { NameServerAddress currentNameServer = nameServers[i]; if (question.Name == currentNameServer.Domain) { continue; //obvious! } if (currentNameServer.EndPoint == null) { resolverStack.Push(new ResolverData(question, nameServers, i)); if (preferIPv6) { question = new DnsQuestionRecord(currentNameServer.Domain, DnsResourceRecordType.AAAA, question.Class); } else { question = new DnsQuestionRecord(currentNameServer.Domain, DnsResourceRecordType.A, question.Class); } nameServers = null; goto stackLoop; } DnsClient client = new DnsClient(currentNameServer); client._proxy = proxy; client._preferIPv6 = preferIPv6; client._tcp = tcp; client._retries = retries; DnsDatagram request = new DnsDatagram(new DnsHeader(0, false, DnsOpcode.StandardQuery, false, false, true, false, false, false, DnsResponseCode.NoError, 1, 0, 0, 0), new DnsQuestionRecord[] { question }, null, null, null); DnsDatagram response; try { response = client.Resolve(request); } catch (DnsClientException) { continue; //resolver loop } if (response.Header.Truncation) { if (tcp) { return(response); } client._tcp = true; response = client.Resolve(request); } if (cache != null) { cache.CacheResponse(response); } switch (response.Header.RCODE) { case DnsResponseCode.NoError: if (response.Answer.Length > 0) { if (!response.Answer[0].Name.Equals(question.Name, StringComparison.CurrentCultureIgnoreCase)) { continue; //continue to next name server since current name server may be misconfigured } if (resolverStack.Count == 0) { return(response); } else { ResolverData data = resolverStack.Pop(); question = data.Question; nameServers = data.NameServers; stackNameServerIndex = data.NameServerIndex; switch (response.Answer[0].Type) { case DnsResourceRecordType.AAAA: nameServers[stackNameServerIndex] = new NameServerAddress(nameServers[stackNameServerIndex].Domain, (response.Answer[0].RDATA as DnsAAAARecord).Address); break; case DnsResourceRecordType.A: nameServers[stackNameServerIndex] = new NameServerAddress(nameServers[stackNameServerIndex].Domain, (response.Answer[0].RDATA as DnsARecord).Address); break; default: //didnt find IP for current name server stackNameServerIndex++; //increment to skip current name server break; } goto resolverLoop; } } if (response.Authority.Length == 0) { continue; //continue to next name server since current name server may be misconfigured } if (response.Authority[0].Type == DnsResourceRecordType.SOA) { //no entry for given type if (resolverStack.Count == 0) { return(response); } else { if (question.Type == DnsResourceRecordType.AAAA) { question = new DnsQuestionRecord(question.Name, DnsResourceRecordType.A, question.Class); } else { //didnt find IP for current name server //pop and try next name server ResolverData data = resolverStack.Pop(); question = data.Question; nameServers = data.NameServers; stackNameServerIndex = data.NameServerIndex + 1; //increment to skip current name server } goto stackLoop; //goto stack loop } } nameServers = NameServerAddress.GetNameServersFromResponse(response, preferIPv6, false); if (nameServers.Length == 0) { continue; //continue to next name server since current name server may be misconfigured } goto resolverLoop; case DnsResponseCode.NameError: if (resolverStack.Count == 0) { return(response); } else { //current name server domain doesnt exists //pop and try next name server ResolverData data = resolverStack.Pop(); question = data.Question; nameServers = data.NameServers; stackNameServerIndex = data.NameServerIndex + 1; //increment to skip current name server goto stackLoop; //goto stack loop } default: continue; //continue to next name server since current name server may be misconfigured } } if (resolverStack.Count == 0) { throw new DnsClientException("DnsClient failed to resolve the request: no response from name servers."); } else { //didnt find IP for current name server //pop and try next name server ResolverData data = resolverStack.Pop(); question = data.Question; nameServers = data.NameServers; stackNameServerIndex = data.NameServerIndex + 1; //increment to skip current name server break; //to stack loop } resolverLoop :; } stackLoop :; } }
protected override void Parse(Stream s) { _preference = DnsDatagram.ReadUInt16NetworkOrder(s); _exchange = DnsDatagram.DeserializeDomainName(s); }
public static DnsDatagram ReadFromJson(dynamic jsonResponse) { DnsDatagram datagram = new DnsDatagram(); datagram._QR = 1; //is response datagram._OPCODE = DnsOpcode.StandardQuery; datagram._TC = (byte)(jsonResponse.TC.Value ? 1 : 0); datagram._RD = (byte)(jsonResponse.RD.Value ? 1 : 0); datagram._RA = (byte)(jsonResponse.RA.Value ? 1 : 0); datagram._AD = (byte)(jsonResponse.AD.Value ? 1 : 0); datagram._CD = (byte)(jsonResponse.CD.Value ? 1 : 0); datagram._RCODE = (DnsResponseCode)jsonResponse.Status; //question if (jsonResponse.Question == null) { datagram._question = Array.Empty <DnsQuestionRecord>(); } else { ushort QDCOUNT = Convert.ToUInt16(jsonResponse.Question.Count); List <DnsQuestionRecord> question = new List <DnsQuestionRecord>(QDCOUNT); datagram._question = question; foreach (dynamic jsonQuestionRecord in jsonResponse.Question) { question.Add(new DnsQuestionRecord(jsonQuestionRecord)); } } //answer if (jsonResponse.Answer == null) { datagram._answer = Array.Empty <DnsResourceRecord>(); } else { ushort ANCOUNT = Convert.ToUInt16(jsonResponse.Answer.Count); List <DnsResourceRecord> answer = new List <DnsResourceRecord>(ANCOUNT); datagram._answer = answer; foreach (dynamic jsonAnswerRecord in jsonResponse.Answer) { answer.Add(new DnsResourceRecord(jsonAnswerRecord)); } } //authority if (jsonResponse.Authority == null) { datagram._authority = Array.Empty <DnsResourceRecord>(); } else { ushort NSCOUNT = Convert.ToUInt16(jsonResponse.Authority.Count); List <DnsResourceRecord> authority = new List <DnsResourceRecord>(NSCOUNT); datagram._authority = authority; foreach (dynamic jsonAuthorityRecord in jsonResponse.Authority) { authority.Add(new DnsResourceRecord(jsonAuthorityRecord)); } } //additional if (jsonResponse.Additional == null) { datagram._additional = Array.Empty <DnsResourceRecord>(); } else { ushort ARCOUNT = Convert.ToUInt16(jsonResponse.Additional.Count); List <DnsResourceRecord> additional = new List <DnsResourceRecord>(ARCOUNT); datagram._additional = additional; foreach (dynamic jsonAdditionalRecord in jsonResponse.Additional) { additional.Add(new DnsResourceRecord(jsonAdditionalRecord)); } } return(datagram); }
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); }
public static DnsDatagram ReadFromUdp(Stream s) { DnsDatagram datagram = new DnsDatagram(); datagram._ID = ReadUInt16NetworkOrder(s); int lB = s.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 = s.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(s); ushort ANCOUNT = ReadUInt16NetworkOrder(s); ushort NSCOUNT = ReadUInt16NetworkOrder(s); ushort ARCOUNT = ReadUInt16NetworkOrder(s); List <DnsQuestionRecord> question = new List <DnsQuestionRecord>(QDCOUNT); List <DnsResourceRecord> answer = new List <DnsResourceRecord>(ANCOUNT); List <DnsResourceRecord> authority = new List <DnsResourceRecord>(NSCOUNT); List <DnsResourceRecord> additional = new List <DnsResourceRecord>(ARCOUNT); try { for (int i = 0; i < QDCOUNT; i++) { question.Add(new DnsQuestionRecord(s)); } for (int i = 0; i < ANCOUNT; i++) { answer.Add(new DnsResourceRecord(s)); } for (int i = 0; i < NSCOUNT; i++) { authority.Add(new DnsResourceRecord(s)); } for (int i = 0; i < ARCOUNT; i++) { additional.Add(new DnsResourceRecord(s)); } } catch (Exception ex) { datagram._parsingException = ex; } datagram._question = question; datagram._answer = answer; datagram._authority = authority; datagram._additional = additional; return(datagram); }
public static NameServerAddress[] GetNameServersFromResponse(DnsDatagram response, bool preferIPv6, bool selectOnlyNameServersWithGlue) { 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) && !selectOnlyNameServersWithGlue) { nameServers.Add(new NameServerAddress(new DomainEndPoint(nsRecord.NSDomainName, 53))); } } } NameServerAddress[] nsArray = nameServers.ToArray(); DnsClient.ShuffleArray(nsArray); if (preferIPv6) { Array.Sort(nsArray); } return(nsArray); }
public abstract DnsDatagram Query(DnsDatagram request);
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); }
protected override void WriteRecordData(Stream s, List <DnsDomainOffset> domainEntries) { DnsDatagram.WriteUInt16NetworkOrder(_preference, s); DnsDatagram.SerializeDomainName(_exchange, s, domainEntries); }
public DnsDatagram Resolve(DnsDatagram request) { int bytesRecv; byte[] responseBuffer = null; int nextServerIndex = 0; int retries = _retries; byte[] requestBuffer; IDnsCache dnsCache = null; //serialize request using (MemoryStream mS = new MemoryStream(32)) { if (_tcp) { mS.Position = 2; } //write dns datagram request.WriteTo(mS); requestBuffer = mS.ToArray(); if (_tcp) { byte[] length = BitConverter.GetBytes(Convert.ToUInt16(requestBuffer.Length - 2)); requestBuffer[0] = length[1]; requestBuffer[1] = length[0]; } } //init server selection parameters if (_servers.Length > 1) { retries = retries * _servers.Length; //retries on per server basis byte[] select = new byte[1]; _rnd.GetBytes(select); nextServerIndex = select[0] % _servers.Length; } int retry = 0; while (retry < retries) { //select server NameServerAddress server; if (_servers.Length > 1) { server = _servers[nextServerIndex]; nextServerIndex = (nextServerIndex + 1) % _servers.Length; } else { server = _servers[0]; } if (server.EndPoint == null) { if (dnsCache == null) { dnsCache = new SimpleDnsCache(); } server.ResolveAddress(dnsCache, _proxy, _preferIPv6, _tcp, _retries); if (server.EndPoint == null) { retry++; continue; } } //query server Socket _socket = null; SocksUdpAssociateRequestHandler proxyRequestHandler = null; try { retry++; DateTime sentAt = DateTime.UtcNow; bool dnsTcp; if (_proxy == null) { if (_tcp) { _socket = new Socket(server.EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); _socket.NoDelay = true; _socket.SendTimeout = _sendTimeout; _socket.ReceiveTimeout = _recvTimeout; IAsyncResult result = _socket.BeginConnect(server.EndPoint, null, null); if (!result.AsyncWaitHandle.WaitOne(_connectionTimeout)) { throw new SocketException((int)SocketError.TimedOut); } if (!_socket.Connected) { throw new SocketException((int)SocketError.ConnectionRefused); } } else { _socket = new Socket(server.EndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Udp); _socket.SendTimeout = _sendTimeout; _socket.ReceiveTimeout = _recvTimeout; } dnsTcp = _tcp; } else { switch (_proxy.Type) { case NetProxyType.Http: _socket = _proxy.HttpProxy.Connect(server.EndPoint, _connectionTimeout); _socket.NoDelay = true; _socket.SendTimeout = _sendTimeout; _socket.ReceiveTimeout = _recvTimeout; dnsTcp = true; break; case NetProxyType.Socks5: if (!_tcp) { try { proxyRequestHandler = _proxy.SocksProxy.UdpAssociate(_connectionTimeout); proxyRequestHandler.ReceiveTimeout = _recvTimeout; dnsTcp = false; break; } catch (SocksClientException) { } } using (SocksConnectRequestHandler requestHandler = _proxy.SocksProxy.Connect(server.EndPoint, _connectionTimeout)) { _socket = requestHandler.GetSocket(); _socket.NoDelay = true; _socket.SendTimeout = _sendTimeout; _socket.ReceiveTimeout = _recvTimeout; dnsTcp = true; } break; default: throw new NotSupportedException("Proxy type not supported by DnsClient."); } } if (dnsTcp) { _socket.Send(requestBuffer); if ((responseBuffer == null) || (responseBuffer.Length == 512)) { responseBuffer = new byte[64 * 1024]; } bytesRecv = _socket.Receive(responseBuffer, 0, 2, SocketFlags.None); if (bytesRecv < 1) { throw new SocketException((int)SocketError.ConnectionReset); } Array.Reverse(responseBuffer, 0, 2); ushort length = BitConverter.ToUInt16(responseBuffer, 0); int offset = 0; while (offset < length) { bytesRecv = _socket.Receive(responseBuffer, offset, length, SocketFlags.None); if (bytesRecv < 1) { throw new SocketException((int)SocketError.ConnectionReset); } offset += bytesRecv; } bytesRecv = length; } else { if (responseBuffer == null) { responseBuffer = new byte[512]; } if (proxyRequestHandler == null) { _socket.SendTo(requestBuffer, server.EndPoint); EndPoint remoteEP; if (server.EndPoint.AddressFamily == AddressFamily.InterNetworkV6) { remoteEP = new IPEndPoint(IPAddress.IPv6Any, 0); } else { remoteEP = new IPEndPoint(IPAddress.Any, 0); } bytesRecv = _socket.ReceiveFrom(responseBuffer, ref remoteEP); } else { proxyRequestHandler.SendTo(requestBuffer, 0, requestBuffer.Length, new SocksEndPoint(server.EndPoint)); bytesRecv = proxyRequestHandler.ReceiveFrom(responseBuffer, 0, responseBuffer.Length, out SocksEndPoint socksRemoteEP); } } //parse response using (MemoryStream mS = new MemoryStream(responseBuffer, 0, bytesRecv, false)) { double rtt = (DateTime.UtcNow - sentAt).TotalMilliseconds; DnsDatagram response = new DnsDatagram(mS, server, (_tcp ? ProtocolType.Tcp : ProtocolType.Udp), rtt); if (response.Header.Identifier == request.Header.Identifier) { return(response); } } } catch (SocketException) { } finally { if (_socket != null) { _socket.Dispose(); } if (proxyRequestHandler != null) { proxyRequestHandler.Dispose(); } } } throw new DnsClientException("DnsClient failed to resolve the request: no response from name servers."); }
public DnsResourceRecord(Stream s) { _name = DnsDatagram.DeserializeDomainName(s); _type = (DnsResourceRecordType)DnsDatagram.ReadUInt16NetworkOrder(s); _class = (DnsClass)DnsDatagram.ReadUInt16NetworkOrder(s); _ttl = DnsDatagram.ReadUInt32NetworkOrder(s); switch (_type) { case DnsResourceRecordType.A: _data = new DnsARecord(s); break; case DnsResourceRecordType.NS: _data = new DnsNSRecord(s); break; case DnsResourceRecordType.CNAME: _data = new DnsCNAMERecord(s); break; case DnsResourceRecordType.SOA: _data = new DnsSOARecord(s); break; case DnsResourceRecordType.PTR: _data = new DnsPTRRecord(s); break; case DnsResourceRecordType.MX: _data = new DnsMXRecord(s); break; case DnsResourceRecordType.TXT: _data = new DnsTXTRecord(s); break; case DnsResourceRecordType.AAAA: _data = new DnsAAAARecord(s); break; case DnsResourceRecordType.SRV: _data = new DnsSRVRecord(s); break; case DnsResourceRecordType.CAA: _data = new DnsCAARecord(s); break; case DnsResourceRecordType.HINFO: _data = new DnsHINFORecord(s); break; case DnsResourceRecordType.ANAME: _data = new DnsANAMERecord(s); break; case DnsResourceRecordType.FWD: _data = new DnsForwarderRecord(s); break; default: _data = new DnsUnknownRecord(s); break; } }
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[] { })); }
public virtual DnsDatagram Query(DnsDatagram request, bool serveStale = false) { if (serveStale) { throw new NotImplementedException("DnsCache does not implement serve stale."); } DnsQuestionRecord question = request.Question[0]; IReadOnlyList <DnsResourceRecord> answerRecords = GetRecords(question.Name, question.Type); if (answerRecords != null) { if (answerRecords[0].RDATA is DnsEmptyRecord) { DnsResourceRecord[] responseAuthority; DnsResourceRecord authority = (answerRecords[0].RDATA as DnsEmptyRecord).Authority; if (authority == null) { responseAuthority = Array.Empty <DnsResourceRecord>(); } else { responseAuthority = new DnsResourceRecord[] { authority } }; return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, responseAuthority)); } if (answerRecords[0].RDATA is DnsNXRecord) { DnsResourceRecord[] responseAuthority; DnsResourceRecord authority = (answerRecords[0].RDATA as DnsNXRecord).Authority; if (authority == null) { responseAuthority = Array.Empty <DnsResourceRecord>(); } else { responseAuthority = new DnsResourceRecord[] { authority } }; return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NameError, request.Question, null, responseAuthority)); } if (answerRecords[0].RDATA is DnsANYRecord) { DnsANYRecord anyRR = answerRecords[0].RDATA as DnsANYRecord; return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, anyRR.Records)); } if (answerRecords[0].RDATA is DnsFailureRecord) { return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, (answerRecords[0].RDATA as DnsFailureRecord).RCODE, request.Question)); } return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answerRecords)); } string currentZone = question.Name; while (currentZone != null) { IReadOnlyList <DnsResourceRecord> nameServers = GetClosestNameServers(currentZone); if (nameServers == null) { break; } List <DnsResourceRecord> glueRecords = new List <DnsResourceRecord>(); foreach (DnsResourceRecord nameServer in nameServers) { string nsDomain = (nameServer.RDATA as DnsNSRecord).NameServer; IReadOnlyList <DnsResourceRecord> glueAs = GetRecords(nsDomain, DnsResourceRecordType.A); if ((glueAs != null) && (glueAs.Count > 0) && (glueAs[0].RDATA is DnsARecord)) { glueRecords.AddRange(glueAs); } IReadOnlyList <DnsResourceRecord> glueAAAAs = GetRecords(nsDomain, DnsResourceRecordType.AAAA); if ((glueAAAAs != null) && (glueAAAAs.Count > 0) && (glueAAAAs[0].RDATA is DnsAAAARecord)) { glueRecords.AddRange(glueAAAAs); } } if (glueRecords.Count > 0) { return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, nameServers, glueRecords)); } currentZone = GetParentZone(currentZone); } return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.Refused, request.Question)); }
public 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); } }
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)); }
public void WriteTo(Stream s, List <DnsDomainOffset> domainEntries) { DnsDatagram.SerializeDomainName(_name, s, domainEntries); DnsDatagram.WriteUInt16NetworkOrder((ushort)_type, s); DnsDatagram.WriteUInt16NetworkOrder((ushort)_class, s); }
protected override void Parse(Stream s) { _nsDomainName = DnsDatagram.ConvertLabelToDomain(s); }
protected override void WriteRecordData(Stream s, List <DnsDomainOffset> domainEntries) { DnsDatagram.SerializeDomainName(_ptrDomainName, s, domainEntries); }
protected override void WriteRecordData(Stream s, List <DnsDomainOffset> domainEntries) { DnsDatagram.ConvertDomainToLabel(_nsDomainName, s, domainEntries); }
public void WriteTo(Stream s, List <DnsDomainOffset> domainEntries) { DnsDatagram.ConvertDomainToLabel(_name, s, domainEntries); DnsDatagram.WriteUInt16NetworkOrder((ushort)_type, s); DnsDatagram.WriteUInt16NetworkOrder((ushort)_class, s); }
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; } }