diff --git a/src/dns/waitfordns.js b/src/dns/waitfordns.js index f9fba81be..b4b54f332 100644 --- a/src/dns/waitfordns.js +++ b/src/dns/waitfordns.js @@ -8,6 +8,28 @@ var assert = require('assert'), dns = require('../native-dns.js'), DomainError = require('../domains.js').DomainError; +function resolveIp(hostname, options, callback) { + assert.strictEqual(typeof hostname, 'string'); + assert.strictEqual(typeof options, 'object'); + assert.strictEqual(typeof callback, 'function'); + + // try A record at authoritative server + debug(`resolveIp: Checking if ${hostname} has A record at ${options.server}`); + dns.resolve(hostname, 'A', options, function (error, results) { + if (!error && results.length !== 0) return callback(null, results); + + // try CNAME record at authoritative server + debug(`resolveIp: Checking if ${hostname} has CNAME record at ${options.server}`); + dns.resolve(hostname, 'CNAME', options, function (error, results) { + if (error || results.length === 0) return callback(error, results); + + // recurse lookup the CNAME record + debug(`resolveIp: Resolving ${hostname}'s CNAME record ${results[0]}`); + dns.resolve(results[0], 'A', { server: '127.0.0.1', timeout: options.timeout }, callback); + }); + }); +} + function isChangeSynced(domain, value, nameserver, callback) { assert.strictEqual(typeof domain, 'string'); assert.strictEqual(typeof value, 'string'); @@ -15,36 +37,27 @@ function isChangeSynced(domain, value, nameserver, callback) { assert.strictEqual(typeof callback, 'function'); // ns records cannot have cname - dns.resolve4(nameserver, function (error, nsIps) { + dns.resolve(nameserver, 'A', { timeout: 5000 }, function (error, nsIps) { if (error || !nsIps || nsIps.length === 0) { - debug('nameserver %s does not resolve. assuming it stays bad.', nameserver); // it's fine if one or more ns are dead + debug(`isChangeSynced: cannot resolve NS ${nameserver}`); // it's fine if one or more ns are dead return callback(null, true); } async.every(nsIps, function (nsIp, iteratorCallback) { - dns.resolve(domain, 'A', { server: nsIp, timeout: 5000 }, function (error, answer) { + resolveIp(domain, { server: nsIp, timeout: 5000 }, function (error, answer) { if (error && error.code === 'TIMEOUT') { - debug('nameserver %s (%s) timed out when trying to resolve %s', nameserver, nsIp, domain); + debug(`isChangeSynced: NS ${nameserver} (${nsIp}) timed out when resolving ${domain}`); return iteratorCallback(null, true); // should be ok if dns server is down } if (error) { - debug('nameserver %s (%s) returned error trying to resolve %s: %s', nameserver, nsIp, domain, error); + debug(`isChangeSynced: NS ${nameserver} (${nsIp}) errored when resolve ${domain}: ${error}`); return iteratorCallback(null, false); } - if (!answer || answer.length === 0) { - debug('bad answer from nameserver %s (%s) resolving %s', nameserver, nsIp, domain); - return iteratorCallback(null, false); - } + debug(`isChangeSynced: ${domain} was resolved to ${answer} at NS ${nameserver} (${nsIp}). Expecting ${value}`); - debug('isChangeSynced: ns: %s (%s), name:%s Actual:%j Expecting:%s', nameserver, nsIp, domain, answer, value); - - var match = answer.some(a => a === value); - - if (match) return iteratorCallback(null, true); // done! - - iteratorCallback(null, false); + iteratorCallback(null, answer.length === 1 && answer[0] === value); }); }, callback); @@ -59,17 +72,18 @@ function waitForDns(domain, zoneName, value, options, callback) { assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 } assert.strictEqual(typeof callback, 'function'); - debug('waitForIp: domain %s to be %s in zone %s.', domain, value, zoneName); + debug('waitForDns: domain %s to be %s in zone %s.', domain, value, zoneName); - var attempt = 1; + var attempt = 0; async.retry(options, function (retryCallback) { - debug('waitForDNS: %s (zone: %s) attempt %s.', domain, zoneName, attempt++); + ++attempt; + debug(`waitForDns (try ${attempt}): ${domain} to be ${value} in zone ${zoneName}`); dns.resolve(zoneName, 'NS', { timeout: 5000 }, function (error, nameservers) { if (error || !nameservers) return retryCallback(error || new DomainError(DomainError.EXTERNAL_ERROR, 'Unable to get nameservers')); async.every(nameservers, isChangeSynced.bind(null, domain, value), function (error, synced) { - debug('waitForIp: %s %s ns: %j', domain, synced ? 'done' : 'not done', nameservers); + debug('waitForDns: %s %s ns: %j', domain, synced ? 'done' : 'not done', nameservers); retryCallback(synced ? null : new DomainError(DomainError.EXTERNAL_ERROR, 'ETRYAGAIN')); }); @@ -77,7 +91,7 @@ function waitForDns(domain, zoneName, value, options, callback) { }, function retryDone(error) { if (error) return callback(error); - debug('waitForDNS: %s done.', domain); + debug(`waitForDns: ${domain} has propagated`); callback(null); }); diff --git a/src/native-dns.js b/src/native-dns.js index 91a1aea50..f37e6cf87 100644 --- a/src/native-dns.js +++ b/src/native-dns.js @@ -1,7 +1,6 @@ 'use strict'; exports = module.exports = { - resolve4: resolve4, resolve: resolve }; @@ -34,7 +33,3 @@ function resolve(hostname, rrtype, options, callback) { callback(error, result); }); } - -function resolve4(hostname, callback) { - resolve(hostname, 'A', { timeout: 5000 }, callback); -}