public void WriteTo(Stream s, List <DnsDomainOffset> domainEntries)
        {
            long originalPosition = s.Position;

            //write dummy RDLENGTH
            s.Write(new byte[] { 0, 0 }, 0, 2);

            //write RDATA
            WriteRecordData(s, domainEntries);

            long finalPosition = s.Position;

            //write actual RDLENGTH
            ushort length = Convert.ToUInt16(finalPosition - originalPosition - 2);

            s.Position = originalPosition;
            DnsDatagram.WriteUInt16NetworkOrder(length, s);

            s.Position = finalPosition;
        }
Exemple #2
0
 protected override void WriteRecordData(Stream s, List <DnsDomainOffset> domainEntries)
 {
     DnsDatagram.SerializeDomainName(_nsDomainName, s, domainEntries);
 }
Exemple #3
0
 protected override void Parse(Stream s)
 {
     _nsDomainName = DnsDatagram.DeserializeDomainName(s);
 }
        public static NameServerAddress[] GetNameServersFromResponse(DnsDatagram response, bool preferIPv6)
        {
            List <NameServerAddress> nameServers = new List <NameServerAddress>(response.Authority.Length);

            DnsResourceRecord[] authorityRecords;

            if ((response.Question.Length > 0) && (response.Question[0].Type == DnsResourceRecordType.NS) && (response.Answer.Length > 0))
            {
                authorityRecords = response.Answer;
            }
            else
            {
                authorityRecords = response.Authority;
            }

            foreach (DnsResourceRecord authorityRecord in authorityRecords)
            {
                if (authorityRecord.Type == DnsResourceRecordType.NS)
                {
                    DnsNSRecord nsRecord = (DnsNSRecord)authorityRecord.RDATA;
                    IPEndPoint  endPoint = null;

                    //find ip address of authoritative name server from additional records
                    foreach (DnsResourceRecord rr in response.Additional)
                    {
                        if (nsRecord.NSDomainName.Equals(rr.Name, StringComparison.OrdinalIgnoreCase))
                        {
                            switch (rr.Type)
                            {
                            case DnsResourceRecordType.A:
                                endPoint = new IPEndPoint(((DnsARecord)rr.RDATA).Address, 53);
                                nameServers.Add(new NameServerAddress(nsRecord.NSDomainName, endPoint));
                                break;

                            case DnsResourceRecordType.AAAA:
                                endPoint = new IPEndPoint(((DnsAAAARecord)rr.RDATA).Address, 53);

                                if (preferIPv6)
                                {
                                    nameServers.Add(new NameServerAddress(nsRecord.NSDomainName, endPoint));
                                }

                                break;
                            }
                        }
                    }

                    if (endPoint == null)
                    {
                        nameServers.Add(new NameServerAddress(new DomainEndPoint(nsRecord.NSDomainName, 53)));
                    }
                }
            }

            NameServerAddress[] nsArray = nameServers.ToArray();

            DnsClient.ShuffleArray(nsArray);

            if (preferIPv6)
            {
                Array.Sort(nsArray);
            }

            return(nsArray);
        }
        public void RecursiveResolveIPAddress(DnsCache cache = null, NetProxy proxy = null, bool preferIPv6 = false, DnsTransportProtocol protocol = DnsTransportProtocol.Udp, int retries = 2, int timeout = 2000, DnsTransportProtocol recursiveResolveProtocol = DnsTransportProtocol.Udp)
        {
            lock (_ipEndPointResolverLock)
            {
                if (_ipEndPointExpires && (DateTime.UtcNow < _ipEndPointExpiresOn))
                {
                    return;
                }

                string domain;

                if (_dohEndPoint != null)
                {
                    domain = _dohEndPoint.Host;
                }
                else if (_domainEndPoint != null)
                {
                    domain = _domainEndPoint.Address;
                }
                else
                {
                    return;
                }

                if (domain == "localhost")
                {
                    _ipEndPoint = new IPEndPoint((preferIPv6 ? IPAddress.IPv6Loopback : IPAddress.Loopback), this.Port);
                    return;
                }

                if (IPAddress.TryParse(domain, out IPAddress address))
                {
                    _ipEndPoint = new IPEndPoint(address, this.Port);
                    return;
                }

                IPEndPoint ipEndPoint          = null;
                DateTime   ipEndPointExpiresOn = DateTime.MinValue;

                if (preferIPv6)
                {
                    DnsDatagram nsResponse = DnsClient.RecursiveResolve(new DnsQuestionRecord(domain, DnsResourceRecordType.AAAA, DnsClass.IN), null, cache, proxy, true, protocol, retries, timeout, recursiveResolveProtocol);
                    if ((nsResponse.Header.RCODE == DnsResponseCode.NoError) && (nsResponse.Answer.Length > 0) && (nsResponse.Answer[0].Type == DnsResourceRecordType.AAAA))
                    {
                        ipEndPoint          = new IPEndPoint((nsResponse.Answer[0].RDATA as DnsAAAARecord).Address, this.Port);
                        ipEndPointExpiresOn = DateTime.UtcNow.AddSeconds(nsResponse.Answer[0].TtlValue);
                    }
                }

                if (ipEndPoint == null)
                {
                    DnsDatagram nsResponse = DnsClient.RecursiveResolve(new DnsQuestionRecord(domain, DnsResourceRecordType.A, DnsClass.IN), null, cache, proxy, false, protocol, retries, timeout, recursiveResolveProtocol);
                    if ((nsResponse.Header.RCODE == DnsResponseCode.NoError) && (nsResponse.Answer.Length > 0) && (nsResponse.Answer[0].Type == DnsResourceRecordType.A))
                    {
                        ipEndPoint          = new IPEndPoint((nsResponse.Answer[0].RDATA as DnsARecord).Address, this.Port);
                        ipEndPointExpiresOn = DateTime.UtcNow.AddSeconds(nsResponse.Answer[0].TtlValue);
                    }
                }

                if (ipEndPoint == null)
                {
                    throw new DnsClientException("No IP address was found for name server: " + domain);
                }

                _ipEndPoint          = ipEndPoint;
                _ipEndPointExpires   = true;
                _ipEndPointExpiresOn = ipEndPointExpiresOn;
            }
        }
Exemple #6
0
 public void WriteTo(Stream s, List <DnsDomainOffset> domainEntries)
 {
     DnsDatagram.SerializeDomainName(_name, s, domainEntries);
     DnsDatagram.WriteUInt16NetworkOrder((ushort)_type, s);
     DnsDatagram.WriteUInt16NetworkOrder((ushort)_class, s);
 }
Exemple #7
0
 public DnsQuestionRecord(Stream s)
 {
     _name  = DnsDatagram.DeserializeDomainName(s);
     _type  = (DnsResourceRecordType)DnsDatagram.ReadUInt16NetworkOrder(s);
     _class = (DnsClass)DnsDatagram.ReadUInt16NetworkOrder(s);
 }
Exemple #8
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);
        }
Exemple #9
0
 public abstract DnsDatagram Query(DnsDatagram request);
Exemple #10
0
 protected override void WriteRecordData(Stream s, List <DnsDomainOffset> domainEntries)
 {
     DnsDatagram.WriteUInt16NetworkOrder(_preference, s);
     DnsDatagram.SerializeDomainName(_exchange, s, domainEntries);
 }
Exemple #11
0
 protected override void Parse(Stream s)
 {
     _preference = DnsDatagram.ReadUInt16NetworkOrder(s);
     _exchange   = DnsDatagram.DeserializeDomainName(s);
 }
Exemple #12
0
        public override DnsDatagram Query(DnsDatagram request)
        {
            DnsQuestionRecord question = request.Question[0];

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

                    if (authority == null)
                    {
                        responseAuthority = new DnsResourceRecord[] { }
                    }
                    ;
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.NoError, 1, 0, 1, 0), request.Question, new DnsResourceRecord[] { }, responseAuthority, new DnsResourceRecord[] { }));
                }

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

                    if (authority == null)
                    {
                        responseAuthority = new DnsResourceRecord[] { }
                    }
                    ;
                    else
                    {
                        responseAuthority = new DnsResourceRecord[] { authority }
                    };

                    return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.NameError, 1, 0, 1, 0), request.Question, new DnsResourceRecord[] { }, responseAuthority, new DnsResourceRecord[] { }));
                }

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

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

                return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.NoError, 1, (ushort)answerRecords.Length, 0, 0), request.Question, answerRecords, new DnsResourceRecord[] { }, new DnsResourceRecord[] { }));
            }

            DnsResourceRecord[] nameServers = GetClosestNameServers(question.Name);
            if (nameServers != null)
            {
                List <DnsResourceRecord> glueRecords = new List <DnsResourceRecord>();

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

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

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

                DnsResourceRecord[] additional = glueRecords.ToArray();

                return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.NoError, 1, 0, (ushort)nameServers.Length, (ushort)additional.Length), request.Question, new DnsResourceRecord[] { }, nameServers, additional));
            }

            return(new DnsDatagram(new DnsHeader(request.Header.Identifier, true, DnsOpcode.StandardQuery, false, false, request.Header.RecursionDesired, true, false, false, DnsResponseCode.Refused, 1, 0, 0, 0), request.Question, new DnsResourceRecord[] { }, new DnsResourceRecord[] { }, new DnsResourceRecord[] { }));
        }