//[DataRow("_acme-challenge.www2.candell.org", "IpualE-HBtD8bxr60LoyuLw8FxMPOIUgg2XQTR6mSvw")] //[DataRow("_acme-challenge.www2.candell.org", "I2F57jex1qSMXprwPy0crWFSUe2n5AowLitxU0q_WKM")] //[DataRow("_acme-challenge.wouter.tinus.online", "DHrsG3LudqI9S0jvitp25tDofK1Jf58J08s3c5rIY3k")] //[DataRow("_acme-challenge.www7.candell.org", "xxx")] public void Should_recursively_follow_cnames(string challengeUri, string expectedToken) { //var client = _dnsClient.DefaultClient(); var client = _dnsClient.GetClients(challengeUri).Result.First(); var tokens = client.GetTextRecordValues(challengeUri, 0).Result; Assert.IsTrue(tokens.Contains(expectedToken)); }
//[DataRow("_acme-challenge.www2.candell.org", "IpualE-HBtD8bxr60LoyuLw8FxMPOIUgg2XQTR6mSvw")] //[DataRow("_acme-challenge.www2.candell.org", "I2F57jex1qSMXprwPy0crWFSUe2n5AowLitxU0q_WKM")] //[DataRow("_acme-challenge.wouter.tinus.online", "DHrsG3LudqI9S0jvitp25tDofK1Jf58J08s3c5rIY3k")] //[DataRow("_acme-challenge.www7.candell.org", "xxx")] public void Should_recursively_follow_cnames(string challengeUri, string expectedToken) { //var client = _dnsClient.DefaultClient(); var client = _dnsClient.GetClients(challengeUri).Result.First(); var(tokens, cname) = client.GetTextRecordValues(challengeUri, 0).Result; Assert.IsTrue(tokens.Contains(expectedToken)); Assert.AreEqual(cname, "_acme-challenge.logs.hourstrackercloud.com"); }
protected async Task <bool> PreValidate(int attempt) { try { var dnsClients = await _dnsClientProvider.GetClients(Challenge.DnsRecordName, attempt); foreach (var client in dnsClients) { _log.Debug("Preliminary validation will now check name server {ip}", client.IpAddress); var answers = await client.GetTextRecordValues(Challenge.DnsRecordName, attempt); if (!answers.Any()) { _log.Warning("Preliminary validation at {address} failed: no TXT records found", client.IpAddress); return(false); } if (!answers.Contains(Challenge.DnsRecordValue)) { _log.Warning("Preliminary validation at {address} failed: {ExpectedTxtRecord} not found in {TxtRecords}", client.IpAddress, Challenge.DnsRecordValue, string.Join(", ", answers)); return(false); } _log.Debug("Preliminary validation at {address} looks good!", client.IpAddress); } } catch (Exception ex) { _log.Error(ex, "Preliminary validation failed"); return(false); } _log.Information("Preliminary validation succeeded"); return(true); }
protected async Task <bool> PreValidate(int attempt) { try { var dnsClients = await _dnsClientProvider.GetClients(_challenge.DnsRecordName, attempt); _log.Debug("Preliminary validation will now check name servers: {address}", string.Join(", ", dnsClients.Select(x => x.IpAddress))); // Parallel queries var answers = await Task.WhenAll(dnsClients.Select(client => client.GetTextRecordValues(_challenge.DnsRecordName, attempt))); // Loop through results for (var i = 0; i < dnsClients.Count(); i++) { var currentClient = dnsClients[i]; var currentResult = answers[i]; if (!currentResult.Any()) { _log.Warning("Preliminary validation for {address} failed: no TXT records found", currentClient.IpAddress); return(false); } if (!currentResult.Contains(_challenge.DnsRecordValue)) { _log.Warning("Preliminary validation for {address} failed: {ExpectedTxtRecord} not found in {TxtRecords}", currentClient.IpAddress, _challenge.DnsRecordValue, string.Join(", ", currentResult)); return(false); } _log.Debug("Preliminary validation for {address} looks good!", currentClient.IpAddress); } } catch (Exception ex) { _log.Error(ex, "Preliminary validation failed"); return(false); } _log.Information("Preliminary validation succeeded"); return(true); }
public override async Task PrepareChallenge() { // Check for substitute domains if (_settings.Validation.AllowDnsSubstitution) { try { // Resolve CNAME in DNS var client = await _dnsClient.GetClients(Challenge.DnsRecordName); var(_, cname) = await client.First().GetTextRecordValues(Challenge.DnsRecordName, 0); // Normalize CNAME var idn = new IdnMapping(); cname = cname.ToLower().Trim().TrimEnd('.'); cname = idn.GetAscii(cname); // Substitute if (cname != Challenge.DnsRecordName) { _log.Information("Detected that {DnsRecordName} is a CNAME that leads to {cname}", Challenge.DnsRecordName, cname); _recordName = cname; } } catch (Exception ex) { _log.Debug("Error checking for substitute domains: {ex}", ex.Message); } } // Create record await CreateRecord(_recordName ?? Challenge.DnsRecordName, Challenge.DnsRecordValue); _log.Information("Answer should now be available at {answerUri}", _recordName); // Verify that the record was created succesfully and wait for possible // propagation/caching/TTL issues to resolve themselves naturally var retry = 0; var maxRetries = _settings.Validation.PreValidateDnsRetryCount; var retrySeconds = _settings.Validation.PreValidateDnsRetryInterval; while (_settings.Validation.PreValidateDns) { if (await PreValidate(retry)) { break; } else { retry += 1; if (retry > maxRetries) { _log.Information("It looks like validation is going to fail, but we will try now anyway..."); break; } else { _log.Information("Will retry in {s} seconds (retry {i}/{j})...", retrySeconds, retry, maxRetries); Thread.Sleep(retrySeconds * 1000); } } } }