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);
        }
Esempio n. 2
0
        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;
        }
Esempio n. 4
0
        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);
 }
Esempio n. 6
0
 protected override void Parse(Stream s)
 {
     _ptrDomainName = DnsDatagram.DeserializeDomainName(s);
 }
Esempio n. 7
0
 public DnsQuestionRecord(Stream s)
 {
     _name  = DnsDatagram.DeserializeDomainName(s);
     _type  = (DnsResourceRecordType)DnsDatagram.ReadUInt16NetworkOrder(s);
     _class = (DnsClass)DnsDatagram.ReadUInt16NetworkOrder(s);
 }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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 :;
            }
        }
Esempio n. 11
0
 protected override void Parse(Stream s)
 {
     _preference = DnsDatagram.ReadUInt16NetworkOrder(s);
     _exchange   = DnsDatagram.DeserializeDomainName(s);
 }
Esempio n. 12
0
        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);
        }
Esempio n. 13
0
        public static async Task <DnsDatagram> ReadFromTcpAsync(Stream stream, MemoryStream sharedBuffer, CancellationToken cancellationToken = default)
        {
            DnsDatagram datagram = new DnsDatagram();

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

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

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

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

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

                ushort length = await ReadUInt16NetworkOrderAsync(stream, cancellationToken);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            return(datagram);
        }
Esempio n. 14
0
        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);
        }
Esempio n. 15
0
        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);
        }
Esempio n. 16
0
 public abstract DnsDatagram Query(DnsDatagram request);
Esempio n. 17
0
        public void CacheResponse(DnsDatagram response)
        {
            if (!response.Header.IsResponse || response.Header.Truncation || (response.Question.Length == 0))
            {
                return; //ineligible response
            }
            switch (response.Header.RCODE)
            {
            case DnsResponseCode.NoError:
            case DnsResponseCode.NameError:
                //cache response after this switch
                break;

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

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

                return;
            }

            //cache only NoError and NameError responses

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

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

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

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

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

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

                            break;

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

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

                            break;
                        }
                    }
                }
            }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                                    break;
                                }
                            }
                        }
                    }

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

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

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

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

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

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

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

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

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

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

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

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

            CacheRecords(cachableRecords);
        }
Esempio n. 18
0
 protected override void WriteRecordData(Stream s, List <DnsDomainOffset> domainEntries)
 {
     DnsDatagram.WriteUInt16NetworkOrder(_preference, s);
     DnsDatagram.SerializeDomainName(_exchange, s, domainEntries);
 }
Esempio n. 19
0
        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.");
        }
Esempio n. 20
0
        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[] { }));
        }
Esempio n. 22
0
        public virtual DnsDatagram Query(DnsDatagram request, bool serveStale = false)
        {
            if (serveStale)
            {
                throw new NotImplementedException("DnsCache does not implement serve stale.");
            }

            DnsQuestionRecord question = request.Question[0];

            IReadOnlyList <DnsResourceRecord> answerRecords = GetRecords(question.Name, question.Type);

            if (answerRecords != null)
            {
                if (answerRecords[0].RDATA is DnsEmptyRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (answerRecords[0].RDATA as DnsEmptyRecord).Authority;

                    if (authority == null)
                    {
                        responseAuthority = Array.Empty <DnsResourceRecord>();
                    }
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, responseAuthority));
                }

                if (answerRecords[0].RDATA is DnsNXRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (answerRecords[0].RDATA as DnsNXRecord).Authority;

                    if (authority == null)
                    {
                        responseAuthority = Array.Empty <DnsResourceRecord>();
                    }
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NameError, request.Question, null, responseAuthority));
                }

                if (answerRecords[0].RDATA is DnsANYRecord)
                {
                    DnsANYRecord anyRR = answerRecords[0].RDATA as DnsANYRecord;
                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, anyRR.Records));
                }

                if (answerRecords[0].RDATA is DnsFailureRecord)
                {
                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, (answerRecords[0].RDATA as DnsFailureRecord).RCODE, request.Question));
                }

                return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answerRecords));
            }

            string currentZone = question.Name;

            while (currentZone != null)
            {
                IReadOnlyList <DnsResourceRecord> nameServers = GetClosestNameServers(currentZone);
                if (nameServers == null)
                {
                    break;
                }

                List <DnsResourceRecord> glueRecords = new List <DnsResourceRecord>();

                foreach (DnsResourceRecord nameServer in nameServers)
                {
                    string nsDomain = (nameServer.RDATA as DnsNSRecord).NameServer;

                    IReadOnlyList <DnsResourceRecord> glueAs = GetRecords(nsDomain, DnsResourceRecordType.A);
                    if ((glueAs != null) && (glueAs.Count > 0) && (glueAs[0].RDATA is DnsARecord))
                    {
                        glueRecords.AddRange(glueAs);
                    }

                    IReadOnlyList <DnsResourceRecord> glueAAAAs = GetRecords(nsDomain, DnsResourceRecordType.AAAA);
                    if ((glueAAAAs != null) && (glueAAAAs.Count > 0) && (glueAAAAs[0].RDATA is DnsAAAARecord))
                    {
                        glueRecords.AddRange(glueAAAAs);
                    }
                }

                if (glueRecords.Count > 0)
                {
                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, nameServers, glueRecords));
                }

                currentZone = GetParentZone(currentZone);
            }

            return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.Refused, request.Question));
        }
Esempio n. 23
0
        public void CacheResponse(DnsDatagram response)
        {
            if (!response.Header.IsResponse)
            {
                return;
            }

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

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

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

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

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

                break;

            default:
                return;     //nothing to do
            }

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

            #region group all records by domain and type

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

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

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

                List <DnsResourceRecord> cacheRREntries;

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

                cacheRREntries.Add(record);
            }

            #endregion

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

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

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

                    CacheEntry(domain, type, records);
                }
            }

            //cache for ANY request
            if (response.Question[0].Type == DnsResourceRecordType.ANY)
            {
                CacheEntry(response.Question[0].Name, DnsResourceRecordType.ANY, response.Answer);
            }
        }
Esempio n. 24
0
        public virtual DnsDatagram Query(DnsDatagram request, bool serveStale = false)
        {
            if (serveStale)
            {
                throw new NotImplementedException("DnsCache does not implement serve stale.");
            }

            DnsQuestionRecord question = request.Question[0];

            IReadOnlyList <DnsResourceRecord> answerRecords = GetRecords(question.Name, question.Type);

            if (answerRecords != null)
            {
                if (answerRecords[0].RDATA is DnsEmptyRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (answerRecords[0].RDATA as DnsEmptyRecord).Authority;

                    if (authority == null)
                    {
                        responseAuthority = Array.Empty <DnsResourceRecord>();
                    }
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, responseAuthority));
                }

                if (answerRecords[0].RDATA is DnsNXRecord)
                {
                    DnsResourceRecord[] responseAuthority;
                    DnsResourceRecord   authority = (answerRecords[0].RDATA as DnsNXRecord).Authority;

                    if (authority == null)
                    {
                        responseAuthority = Array.Empty <DnsResourceRecord>();
                    }
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NameError, request.Question, null, responseAuthority));
                }

                if (answerRecords[0].RDATA is DnsANYRecord)
                {
                    DnsANYRecord anyRR = answerRecords[0].RDATA as DnsANYRecord;
                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, anyRR.Records));
                }

                if (answerRecords[0].RDATA is DnsFailureRecord)
                {
                    return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, (answerRecords[0].RDATA as DnsFailureRecord).RCODE, request.Question));
                }

                IReadOnlyList <DnsResourceRecord> additionalRecords = null;

                switch (question.Type)
                {
                case DnsResourceRecordType.NS:
                case DnsResourceRecordType.MX:
                case DnsResourceRecordType.SRV:
                    additionalRecords = GetAdditionalRecords(answerRecords);
                    break;
                }

                return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, answerRecords, null, additionalRecords));
            }

            IReadOnlyList <DnsResourceRecord> closestAuthority = GetClosestNameServers(question.Name);

            if (closestAuthority != null)
            {
                IReadOnlyList <DnsResourceRecord> additionalRecords = GetAdditionalRecords(closestAuthority);

                return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.NoError, request.Question, null, closestAuthority, additionalRecords));
            }

            return(new DnsDatagram(request.Identifier, true, DnsOpcode.StandardQuery, false, false, request.RecursionDesired, true, false, false, DnsResponseCode.Refused, request.Question));
        }
Esempio n. 25
0
 public void WriteTo(Stream s, List <DnsDomainOffset> domainEntries)
 {
     DnsDatagram.SerializeDomainName(_name, s, domainEntries);
     DnsDatagram.WriteUInt16NetworkOrder((ushort)_type, s);
     DnsDatagram.WriteUInt16NetworkOrder((ushort)_class, s);
 }
Esempio n. 26
0
 protected override void Parse(Stream s)
 {
     _nsDomainName = DnsDatagram.ConvertLabelToDomain(s);
 }
Esempio n. 27
0
 protected override void WriteRecordData(Stream s, List <DnsDomainOffset> domainEntries)
 {
     DnsDatagram.SerializeDomainName(_ptrDomainName, s, domainEntries);
 }
Esempio n. 28
0
 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);
 }
Esempio n. 30
0
        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;
            }
        }