예제 #1
0
        /// <summary>
        /// Finds the Autodiscover host from DNS SRV records.
        /// </summary>
        /// <remarks>
        /// If the domain to lookup is "contoso.com", Autodiscover will use DnsQuery on SRV records
        /// for "_autodiscover._tcp.contoso.com". If the query is successful it will return a target
        /// domain (e.g. "mail.contoso.com") which will be tried as an Autodiscover endpoint.
        /// </remarks>
        /// <param name="domain">The domain.</param>
        /// <returns>Autodiscover hostname (will be null if lookup failed).</returns>
        internal string FindAutodiscoverHostFromSrv(string domain)
        {
            string domainToMatch = AutoDiscoverSrvPrefix + domain;

            DnsSrvRecord dnsSrvRecord = this.FindBestMatchingSrvRecord(domainToMatch);

            if ((dnsSrvRecord == null) || string.IsNullOrEmpty(dnsSrvRecord.NameTarget))
            {
                this.service.TraceMessage(
                    TraceFlags.AutodiscoverConfiguration,
                    "No appropriate SRV record was found.");
                return(null);
            }
            else
            {
                this.service.TraceMessage(
                    TraceFlags.AutodiscoverConfiguration,
                    string.Format("DNS query for SRV record for domain {0} found {1}", domain, dnsSrvRecord.NameTarget));

                return(dnsSrvRecord.NameTarget);
            }
        }
예제 #2
0
        /// <summary>
        /// Finds the best matching SRV record.
        /// </summary>
        /// <param name="domain">The domain.</param>
        /// <returns>DnsSrvRecord(will be null if lookup failed).</returns>
        private DnsSrvRecord FindBestMatchingSrvRecord(string domain)
        {
            List <DnsSrvRecord> dnsSrvRecordList;

            try
            {
                // Make DnsQuery call to get collection of SRV records.
                dnsSrvRecordList = DnsClient.DnsQuery <DnsSrvRecord>(domain, this.service.DnsServerAddress);
            }
            catch (DnsException ex)
            {
                string dnsExcMessage = string.Format(
                    "DnsQuery returned error error '{0}' error code 0x{1:X8}.",
                    ex.Message,
                    ex.NativeErrorCode);
                this.service.TraceMessage(TraceFlags.AutodiscoverConfiguration, dnsExcMessage);
                return(null);
            }
            catch (SecurityException ex)
            {
                // In restricted environments, we may not be allowed to call unmanaged code.
                this.service.TraceMessage(
                    TraceFlags.AutodiscoverConfiguration,
                    string.Format("DnsQuery cannot be called. Security error: {0}.", ex.Message));
                return(null);
            }

            this.service.TraceMessage(
                TraceFlags.AutodiscoverConfiguration,
                string.Format("{0} SRV records were returned.", dnsSrvRecordList.Count));

            // If multiple records were returned, they will be returned sorted by priority
            // (and weight) order. Need to find the index of the first record that supports SSL.
            int  priority    = int.MinValue;
            int  weight      = int.MinValue;
            bool recordFound = false;

            foreach (DnsSrvRecord dnsSrvRecord in dnsSrvRecordList)
            {
                if (dnsSrvRecord.Port == SslPort)
                {
                    priority    = dnsSrvRecord.Priority;
                    weight      = dnsSrvRecord.Weight;
                    recordFound = true;
                    break;
                }
            }

            // Records were returned but nothing matched our criteria.
            if (!recordFound)
            {
                this.service.TraceMessage(
                    TraceFlags.AutodiscoverConfiguration,
                    "No appropriate SRV records were found.");

                return(null);
            }

            // Collect all records with the same (highest) priority.
            // (Aren't lambda expressions cool? ;-)
            List <DnsSrvRecord> bestDnsSrvRecordList = dnsSrvRecordList.FindAll(
                record => (record.Port == SslPort) && (record.Priority == priority) && (record.Weight == weight));

            // The list must contain at least one matching record since we found one earlier.
            EwsUtilities.Assert(
                dnsSrvRecordList.Count > 0,
                "AutodiscoverDnsClient.FindBestMatchingSrvRecord",
                "At least one DNS SRV record must match the criteria.");

            // If we have multiple records with the same priority and weight, randomly pick one.
            int recordIndex = (bestDnsSrvRecordList.Count > 1)
                ? randomTieBreakerSelector.Next(bestDnsSrvRecordList.Count)
                : 0;

            DnsSrvRecord bestDnsSrvRecord = bestDnsSrvRecordList[recordIndex];

            string traceMessage = string.Format(
                "Returning SRV record {0} of {1} records. Target: {2}, Priority: {3}, Weight: {4}",
                recordIndex,
                dnsSrvRecordList.Count,
                bestDnsSrvRecord.NameTarget,
                bestDnsSrvRecord.Priority,
                bestDnsSrvRecord.Weight);

            this.service.TraceMessage(TraceFlags.AutodiscoverConfiguration, traceMessage);

            return(bestDnsSrvRecord);
        }