Esempio n. 1
0
        public async Task <List <IPAddress> > ResolveMxIpAddressesAsync(string domainName)
        {
            var hostNames = await ResolveMxHostNamesAsync(domainName);

            var result = new List <IPAddress>();

            foreach (var hostName in hostNames)
            {
                // TODO: Query for IPV6 as well.
                var dnsMessage = await _dnsClient.ResolveAsync(DomainName.Parse(hostName), RecordType.A);

                if (IsFailedQuery(dnsMessage))
                {
                    // TODO: Throw specific type
                    throw new Exception($"Dns query for {domainName} failed.");
                }

                var aRecords =
                    dnsMessage.AnswerRecords.OfType <ARecord>();

                result.AddRange(from record in aRecords
                                select record.Address);
            }

            return(result);
        }
        } // End Function ResolveMessage

        static async Task ForwardMessage(DnsMessage query, QueryReceivedEventArgs e, DnsMessage response)
        {
            if ((query.Questions.Count == 1))
            {
                // send query to upstream server
                DnsQuestion question = query.Questions[0];

                DnsMessage upstreamResponse = await s_dnsClient.ResolveAsync(question.Name
                                                                             , question.RecordType, question.RecordClass
                                                                             );

                e.Response = upstreamResponse;
                return;


                // if got an answer, copy it to the message sent to the client
                if (upstreamResponse != null)
                {
                    foreach (DnsRecordBase record in (upstreamResponse.AnswerRecords))
                    {
                        response.AnswerRecords.Add(record);
                    } // Next record

                    foreach (DnsRecordBase record in (upstreamResponse.AdditionalRecords))
                    {
                        response.AdditionalRecords.Add(record);
                    } // Next record

                    response.ReturnCode = ReturnCode.NoError;

                    // set the response
                    e.Response = response;
                } // End if (upstreamResponse != null)
            }     // End if ((message.Questions.Count == 1))
        }         // End Function OnQueryReceived
        /// <summary>
        ///   Queries a the upstream DNS server(s) for specified records as an asynchronous operation.
        /// </summary>
        /// <typeparam name="T"> Type of records, that should be returned </typeparam>
        /// <param name="name"> Domain, that should be queried </param>
        /// <param name="recordType"> Type the should be queried </param>
        /// <param name="recordClass"> Class the should be queried </param>
        /// <param name="token"> The token to monitor cancellation requests </param>
        /// <returns> A list of matching <see cref="DnsRecordBase">records</see> </returns>
        public async Task <List <T> > ResolveAsync <T>(DomainName name, RecordType recordType = RecordType.A, RecordClass recordClass = RecordClass.INet, CancellationToken token = default(CancellationToken))
            where T : DnsRecordBase
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name), "Name must be provided");
            }

            List <T> records;

            if (_cache.TryGetRecords(name, recordType, recordClass, out records))
            {
                return(records);
            }

            DnsMessage msg = await _dnsClient.ResolveAsync(name, recordType, recordClass, null, token);

            if ((msg == null) || ((msg.ReturnCode != ReturnCode.NoError) && (msg.ReturnCode != ReturnCode.NxDomain)))
            {
                throw new Exception("DNS request failed");
            }

            CNameRecord cName = msg.AnswerRecords.Where(x => (x.RecordType == RecordType.CName) && (x.RecordClass == recordClass) && x.Name.Equals(name)).OfType <CNameRecord>().FirstOrDefault();

            if (cName != null)
            {
                records = msg.AnswerRecords.Where(x => (x.RecordType == recordType) && (x.RecordClass == recordClass) && x.Name.Equals(cName.CanonicalName)).OfType <T>().ToList();
                if (records.Count > 0)
                {
                    _cache.Add(name, recordType, recordClass, records, DnsSecValidationResult.Indeterminate, Math.Min(cName.TimeToLive, records.Min(x => x.TimeToLive)));
                    return(records);
                }

                records = await ResolveAsync <T>(cName.CanonicalName, recordType, recordClass, token);

                if (records.Count > 0)
                {
                    _cache.Add(name, recordType, recordClass, records, DnsSecValidationResult.Indeterminate, Math.Min(cName.TimeToLive, records.Min(x => x.TimeToLive)));
                }

                return(records);
            }

            records = msg.AnswerRecords.Where(x => x.Name.Equals(name)).OfType <T>().ToList();

            if (records.Count > 0)
            {
                _cache.Add(name, recordType, recordClass, records, DnsSecValidationResult.Indeterminate, records.Min(x => x.TimeToLive));
            }

            return(records);
        }
Esempio n. 4
0
        /// <summary>
        ///   Resolves specified records as an asynchronous operation.
        /// </summary>
        /// <typeparam name="T"> Type of records, that should be returned </typeparam>
        /// <param name="name"> Domain, that should be queried </param>
        /// <param name="recordType"> Type the should be queried </param>
        /// <param name="recordClass"> Class the should be queried </param>
        /// <param name="token"> The token to monitor cancellation requests </param>
        /// <returns> A list of matching <see cref="DnsRecordBase">records</see> </returns>
        public async Task <DnsSecResult <T> > ResolveSecureAsync <T>(DomainName name, RecordType recordType = RecordType.A, RecordClass recordClass = RecordClass.INet, CancellationToken token = default(CancellationToken))
            where T : DnsRecordBase
        {
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name), "Name must be provided");
            }

            DnsCacheRecordList <T> cacheResult;

            if (_cache.TryGetRecords(name, recordType, recordClass, out cacheResult))
            {
                return(new DnsSecResult <T>(cacheResult, cacheResult.ValidationResult));
            }

            DnsMessage msg = await _dnsClient.ResolveAsync(name, recordType, recordClass, new DnsQueryOptions()
            {
                IsEDnsEnabled      = true,
                IsDnsSecOk         = true,
                IsCheckingDisabled = true,
                IsRecursionDesired = true
            }, token).ConfigureAwait(false);

            if ((msg == null) || ((msg.ReturnCode != ReturnCode.NoError) && (msg.ReturnCode != ReturnCode.NxDomain)))
            {
                throw new Exception("DNS request failed");
            }

            DnsSecValidationResult validationResult;

            CNameRecord cName = msg.AnswerRecords.Where(x => (x.RecordType == RecordType.CName) && (x.RecordClass == recordClass) && x.Name.Equals(name)).OfType <CNameRecord>().FirstOrDefault();

            if (cName != null)
            {
                DnsSecValidationResult cNameValidationResult = await _validator.ValidateAsync(name, RecordType.CName, recordClass, msg, new List <CNameRecord>() { cName }, null, token).ConfigureAwait(false);

                if ((cNameValidationResult == DnsSecValidationResult.Bogus) || (cNameValidationResult == DnsSecValidationResult.Indeterminate))
                {
                    throw new DnsSecValidationException("CNAME record could not be validated");
                }

                var records = msg.AnswerRecords.Where(x => (x.RecordType == recordType) && (x.RecordClass == recordClass) && x.Name.Equals(cName.CanonicalName)).OfType <T>().ToList();
                if (records.Count > 0)
                {
                    DnsSecValidationResult recordsValidationResult = await _validator.ValidateAsync(cName.CanonicalName, recordType, recordClass, msg, records, null, token).ConfigureAwait(false);

                    if ((recordsValidationResult == DnsSecValidationResult.Bogus) || (recordsValidationResult == DnsSecValidationResult.Indeterminate))
                    {
                        throw new DnsSecValidationException("CNAME matching records could not be validated");
                    }

                    validationResult = cNameValidationResult == recordsValidationResult ? cNameValidationResult : DnsSecValidationResult.Unsigned;
                    _cache.Add(name, recordType, recordClass, records, validationResult, Math.Min(cName.TimeToLive, records.Min(x => x.TimeToLive)));

                    return(new DnsSecResult <T>(records, validationResult));
                }

                var cNameResults = await ResolveSecureAsync <T>(cName.CanonicalName, recordType, recordClass, token).ConfigureAwait(false);

                validationResult = cNameValidationResult == cNameResults.ValidationResult ? cNameValidationResult : DnsSecValidationResult.Unsigned;

                if (cNameResults.Records.Count > 0)
                {
                    _cache.Add(name, recordType, recordClass, cNameResults.Records, validationResult, Math.Min(cName.TimeToLive, cNameResults.Records.Min(x => x.TimeToLive)));
                }

                return(new DnsSecResult <T>(cNameResults.Records, validationResult));
            }

            List <T> res = msg.AnswerRecords.Where(x => (x.RecordType == recordType) && (x.RecordClass == recordClass) && x.Name.Equals(name)).OfType <T>().ToList();

            validationResult = await _validator.ValidateAsync(name, recordType, recordClass, msg, res, null, token).ConfigureAwait(false);

            if ((validationResult == DnsSecValidationResult.Bogus) || (validationResult == DnsSecValidationResult.Indeterminate))
            {
                throw new DnsSecValidationException("Response records could not be validated");
            }

            if (res.Count > 0)
            {
                _cache.Add(name, recordType, recordClass, res, validationResult, res.Min(x => x.TimeToLive));
            }

            return(new DnsSecResult <T>(res, validationResult));
        }
Esempio n. 5
0
        private async Task Server_QueryReceived(object sender, ARSoft.Tools.Net.Dns.QueryReceivedEventArgs e)
        {
            bool foundQuery = false;

            DnsMessage query = e.Query as DnsMessage;

            if (query == null)
            {
                return;
            }

            DnsMessage response = query.CreateResponseInstance();

            try {
                C.WriteLine($"DnsServer: Questions: {query.Questions.Count}", true, "DNS");

                for (int idx = 0; idx < query.Questions.Count; idx++)
                {
                    var question = query.Questions[idx];

                    using (var connection = db.Connection()) {
                        using (var command = new SqliteCommand(
                                   "SELECT * FROM DnsEntries WHERE RecordType = @RecordType AND RecordClass = @RecordClass AND DomainName = @DomainName;", connection)) {
                            command.Parameters.AddWithValue("@RecordType", question.RecordType.ToString());
                            command.Parameters.AddWithValue("@RecordClass", question.RecordClass.ToString());
                            command.Parameters.AddWithValue("@DomainName", question.Name.ToString());

                            using (var reader = command.ExecuteReader()) {
                                C.WriteLine($"  Questions [{idx:000}] RES({reader.HasRows}): Type({question.RecordType}), Class({question.RecordClass}), {question.Name}", true, "DNS");

                                //Every new row will create a new dictionary that holds the columns
                                while (reader.Read())
                                {
                                    try {
                                        var dnStr = reader["DomainName"] as string;
                                        var dn    = DomainName.Parse(dnStr);
                                        if (dn == null)
                                        {
                                            continue;
                                        }

                                        var ttl = (System.Int64)reader["TTL"];
                                        var rt  = (RecordType)Enum.Parse(typeof(RecordType), reader["RecordType"] as string);
                                        var rc  = (RecordClass)Enum.Parse(typeof(RecordClass), reader["RecordClass"] as string);

                                        if (rt == RecordType.A)
                                        {
                                            if (reader["Address"] == null)
                                            {
                                                continue;
                                            }
                                            var addr = reader["Address"] as string;

                                            var aRec = new ARecord(dn, Convert.ToInt32(ttl), IPAddress.Parse(addr));
                                            response.AnswerRecords.Add(aRec);

                                            foundQuery = true;
                                        }
                                    } catch (Exception ex) {
                                        C.WriteLine($"  Questions [{idx:000}]: {C.Red}Exception: {ex.ToString()}", true, "DNS:ERROR");
                                    }
                                }
                            }
                        }
                    }
                }

                // Fallback
                if (dnsFallback != null && !foundQuery)
                {
                    DnsQuestion question = query.Questions[0];
                    var         resolve  = dnsFallback.Resolve(question.Name);

                    DnsMessage upstreamResponse = await dnsFallback.ResolveAsync(
                        question.Name, question.RecordType, question.RecordClass);

                    e.Response = upstreamResponse;
                    return;
                }

                response.ReturnCode = ReturnCode.NoError;
            } catch (Exception ex) {
                response.ReturnCode = ReturnCode.ServerFailure;
                C.WriteLine($"{C.Red}{ex.ToString()}", true, "DNS:ERROR");
            }

            // set the response
            e.Response = response;
        }