/// <summary>
        /// Get cached list of authoritative name server ip addresses
        /// </summary>
        /// <param name="domainName"></param>
        /// <param name="round"></param>
        /// <returns></returns>
        public async Task <DnsLookupResult> GetAuthority(string domainName, int round = 0, bool followCnames = true, DnsLookupResult?from = null)
        {
            var key = domainName.ToLower().TrimEnd('.');

            try
            {
                // Example: _acme-challenge.sub.example.co.uk
                domainName = domainName.TrimEnd('.');

                // First domain we should try to ask is the tld (e.g. co.uk)
                var rootDomain = _domainParser.GetTLD(domainName);
                var testZone   = rootDomain;
                var client     = GetDefaultClient(round);

                // Other sub domains we should ask:
                // 1. example
                // 1. sub
                // 2. _acme-challenge
                var remainingParts = domainName.Substring(0, domainName.LastIndexOf(rootDomain))
                                     .Trim('.').Split('.').Where(x => !string.IsNullOrEmpty(x))
                                     .Reverse().ToArray();

                var digDeeper = true;
                IEnumerable <IPAddress>?ipSet = null;
                do
                {
                    // Partial result cachign
                    if (!_authoritativeNs.ContainsKey(testZone))
                    {
                        _log.Verbose("Querying server {server} about {part}", client.IpAddress, testZone);
                        using (LogContext.PushProperty("Domain", testZone))
                        {
                            var tempResult = await client.GetNameServers(testZone, round);

                            _authoritativeNs.TryAdd(testZone, tempResult?.ToList() ?? ipSet ?? _defaultNs);
                        }
                    }
                    ipSet  = _authoritativeNs[testZone];
                    client = Produce(ipSet.OrderBy(x => Guid.NewGuid()).First());

                    // CNAME only valid for full domain. Subdomains may be
                    // regular records again
                    if (followCnames && testZone == key)
                    {
                        var cname = default(string?);
                        if (!_cnames.ContainsKey(key))
                        {
                            _cnames.TryAdd(key, await client.GetCname(testZone));
                        }
                        cname = _cnames[key];
                        if (cname != null)
                        {
                            return(await GetAuthority(cname, round, true, Produce(key, from)));
                        }
                    }

                    if (remainingParts.Any())
                    {
                        testZone       = $"{remainingParts[0]}.{testZone}";
                        remainingParts = remainingParts[1..];
 private string?GetTldCache(string domain)
 {
     if (_tldCache.TryGetValue(domain, out var value))
     {
         return(value);
     }
     value = _domainParser.GetTLD(domain);
     _tldCache.Add(domain, value);
     return(value);
 }
 private string?GetTldCache(string domain)
 {
     if (_tldCache.TryGetValue(domain, out var value))
     {
         return(value);
     }
     try
     {
         value = _domainParser.GetTLD(domain);
         _tldCache.Add(domain, value);
     }
     catch
     {
         value = ".error";
         _tldCache.Add(domain, value);
     }
     return(value);
 }
 public string GetRootDomain(string domainName) => _domainParser.GetTLD(domainName.TrimEnd('.'));
        /// <summary>
        /// Get cached list of authoritative name server ip addresses
        /// </summary>
        /// <param name="domainName"></param>
        /// <param name="round"></param>
        /// <returns></returns>
        public async Task <DnsLookupResult> GetAuthority(string domainName, int round = 0, bool followCnames = true)
        {
            var key = domainName.ToLower().TrimEnd('.');

            if (!_authoritativeNs.ContainsKey(key))
            {
                try
                {
                    // Example: _acme-challenge.sub.example.co.uk
                    domainName = domainName.TrimEnd('.');

                    // First domain we should try to ask is the tld (e.g. co.uk)
                    var rootDomain = _domainParser.GetTLD(domainName);
                    var testZone   = rootDomain;
                    var client     = GetDefaultClient(round);

                    // Other sub domains we should ask:
                    // 1. example
                    // 1. sub
                    // 2. _acme-challenge
                    var remainingParts = domainName.Substring(0, domainName.LastIndexOf(rootDomain))
                                         .Trim('.').Split('.')
                                         .Where(x => !string.IsNullOrEmpty(x));
                    remainingParts = remainingParts.Reverse();

                    var digDeeper = true;
                    IEnumerable <IPAddress>?ipSet = null;
                    do
                    {
                        // Partial result cachign
                        if (!_authoritativeNs.ContainsKey(testZone))
                        {
                            _log.Verbose("Querying server {server} about {part}", client.IpAddress, testZone);
                            using (LogContext.PushProperty("Domain", testZone))
                            {
                                var tempResult = await client.GetNameServers(testZone, round);

                                _authoritativeNs.Add(testZone, tempResult?.ToList() ?? ipSet ?? _defaultNs);
                            }
                        }
                        ipSet  = _authoritativeNs[testZone];
                        client = Produce(ipSet.OrderBy(x => Guid.NewGuid()).First());

                        // CNAME only valid for full domain. Subdomains may be
                        // regular records again
                        if (followCnames && testZone == key)
                        {
                            var cname = await client.GetCname(testZone);

                            if (cname != null)
                            {
                                return(await GetAuthority(cname, round));
                            }
                        }

                        if (remainingParts.Any())
                        {
                            testZone       = $"{remainingParts.First()}.{testZone}";
                            remainingParts = remainingParts.Skip(1).ToArray();
                        }
                        else
                        {
                            digDeeper = false;
                        }
                    }while (digDeeper);

                    if (ipSet == null)
                    {
                        throw new Exception("No results");
                    }
                }
                catch (Exception ex)
                {
                    _log.Warning("Unable to find or contact authoritative name servers for {domainName}: {message}", domainName, ex.Message);
                    _authoritativeNs.Add(key, _defaultNs);
                }
            }
            return(new DnsLookupResult(key, _authoritativeNs[key].Select(ip => Produce(ip))));
        }
Exemple #6
0
        /// <summary>
        /// Get cached list of authoritative name server ip addresses
        /// </summary>
        /// <param name="domainName"></param>
        /// <param name="round"></param>
        /// <returns></returns>
        private async Task <IEnumerable <IPAddress> > GetAuthoritativeNameServersForDomain(string domainName, int round)
        {
            var key = domainName.ToLower().TrimEnd('.');

            if (!_authoritativeNs.ContainsKey(key))
            {
                try
                {
                    // _acme-challenge.sub.example.co.uk
                    domainName = domainName.TrimEnd('.');

                    // First domain we should try to ask
                    var rootDomain = _domainParser.GetTLD(domainName);
                    var testZone   = rootDomain;
                    var client     = GetDefaultClient(round);

                    // Other sub domains we should try asking:
                    // 1. sub
                    // 2. _acme-challenge
                    var remainingParts = domainName.Substring(0, domainName.LastIndexOf(rootDomain))
                                         .Trim('.').Split('.')
                                         .Where(x => !string.IsNullOrEmpty(x));
                    remainingParts = remainingParts.Reverse();

                    var digDeeper = true;
                    IEnumerable <IPAddress>?ipSet = null;
                    do
                    {
                        // Partial result cachign
                        if (!_authoritativeNs.ContainsKey(testZone))
                        {
                            _log.Verbose("Querying server {server} about {part}", client.IpAddress, testZone);
                            using (LogContext.PushProperty("Domain", testZone))
                            {
                                var tempResult = await client.GetAuthoritativeNameServers(testZone, round);

                                _authoritativeNs.Add(testZone, tempResult?.ToList() ?? ipSet ?? _defaultNs);
                            }
                        }
                        ipSet  = _authoritativeNs[testZone];
                        client = Produce(ipSet.OrderBy(x => Guid.NewGuid()).First());
                        if (remainingParts.Any())
                        {
                            testZone       = $"{remainingParts.First()}.{testZone}";
                            remainingParts = remainingParts.Skip(1).ToArray();
                        }
                        else
                        {
                            digDeeper = false;
                        }
                    }while (digDeeper);

                    if (ipSet == null)
                    {
                        throw new Exception("No results");
                    }
                }
                catch (Exception ex)
                {
                    _log.Warning("Unable to find or contact authoritative name servers for {domainName}: {message}", domainName, ex.Message);
                    _authoritativeNs.Add(key, _defaultNs);
                }
            }
            return(_authoritativeNs[key]);
        }