2015-12-11 13:14:27 -08:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
exports = module.exports = waitForDns;
|
|
|
|
|
|
|
|
|
|
var assert = require('assert'),
|
|
|
|
|
async = require('async'),
|
2016-12-14 12:27:11 -08:00
|
|
|
debug = require('debug')('box:dns/waitfordns'),
|
2018-02-08 10:21:31 -08:00
|
|
|
dns = require('../native-dns.js'),
|
2018-04-29 11:20:12 -07:00
|
|
|
DomainsError = require('../domains.js').DomainsError;
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2018-02-08 14:55:06 -08:00
|
|
|
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);
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-08 14:19:14 -08:00
|
|
|
function isChangeSynced(domain, value, nameserver, callback) {
|
2015-12-11 13:14:27 -08:00
|
|
|
assert.strictEqual(typeof domain, 'string');
|
2018-02-08 14:19:14 -08:00
|
|
|
assert.strictEqual(typeof value, 'string');
|
2015-12-11 13:14:27 -08:00
|
|
|
assert.strictEqual(typeof nameserver, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
// ns records cannot have cname
|
2018-02-08 14:55:06 -08:00
|
|
|
dns.resolve(nameserver, 'A', { timeout: 5000 }, function (error, nsIps) {
|
2016-04-25 15:58:42 -07:00
|
|
|
if (error || !nsIps || nsIps.length === 0) {
|
2018-02-08 14:55:06 -08:00
|
|
|
debug(`isChangeSynced: cannot resolve NS ${nameserver}`); // it's fine if one or more ns are dead
|
2018-02-08 14:10:32 -08:00
|
|
|
return callback(null, true);
|
2016-04-25 15:58:42 -07:00
|
|
|
}
|
2015-12-11 13:14:27 -08:00
|
|
|
|
|
|
|
|
async.every(nsIps, function (nsIp, iteratorCallback) {
|
2018-02-08 14:55:06 -08:00
|
|
|
resolveIp(domain, { server: nsIp, timeout: 5000 }, function (error, answer) {
|
2018-02-08 14:27:02 -08:00
|
|
|
if (error && error.code === 'TIMEOUT') {
|
2018-02-08 14:55:06 -08:00
|
|
|
debug(`isChangeSynced: NS ${nameserver} (${nsIp}) timed out when resolving ${domain}`);
|
2017-05-26 15:15:01 -07:00
|
|
|
return iteratorCallback(null, true); // should be ok if dns server is down
|
|
|
|
|
}
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2016-04-25 16:00:49 -07:00
|
|
|
if (error) {
|
2018-02-08 14:55:06 -08:00
|
|
|
debug(`isChangeSynced: NS ${nameserver} (${nsIp}) errored when resolve ${domain}: ${error}`);
|
2017-02-16 20:11:09 -08:00
|
|
|
return iteratorCallback(null, false);
|
2016-04-25 16:00:49 -07:00
|
|
|
}
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2018-02-08 14:55:06 -08:00
|
|
|
debug(`isChangeSynced: ${domain} was resolved to ${answer} at NS ${nameserver} (${nsIp}). Expecting ${value}`);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2018-02-08 14:55:06 -08:00
|
|
|
iteratorCallback(null, answer.length === 1 && answer[0] === value);
|
2015-12-11 13:14:27 -08:00
|
|
|
});
|
|
|
|
|
}, callback);
|
2017-05-26 15:15:01 -07:00
|
|
|
|
2015-12-11 13:14:27 -08:00
|
|
|
});
|
2018-01-09 16:09:47 -08:00
|
|
|
}
|
2015-12-11 13:14:27 -08:00
|
|
|
|
|
|
|
|
// check if IP change has propagated to every nameserver
|
2018-02-08 14:19:14 -08:00
|
|
|
function waitForDns(domain, zoneName, value, options, callback) {
|
2015-12-11 13:14:27 -08:00
|
|
|
assert.strictEqual(typeof domain, 'string');
|
2017-06-11 22:12:23 -07:00
|
|
|
assert.strictEqual(typeof zoneName, 'string');
|
2018-02-08 14:19:14 -08:00
|
|
|
assert.strictEqual(typeof value, 'string');
|
2016-06-21 15:12:36 -05:00
|
|
|
assert(options && typeof options === 'object'); // { interval: 5000, times: 50000 }
|
2016-04-22 16:04:29 -07:00
|
|
|
assert.strictEqual(typeof callback, 'function');
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2018-02-08 14:55:06 -08:00
|
|
|
debug('waitForDns: domain %s to be %s in zone %s.', domain, value, zoneName);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2018-02-08 14:55:06 -08:00
|
|
|
var attempt = 0;
|
2016-06-21 15:12:36 -05:00
|
|
|
async.retry(options, function (retryCallback) {
|
2018-02-08 14:55:06 -08:00
|
|
|
++attempt;
|
|
|
|
|
debug(`waitForDns (try ${attempt}): ${domain} to be ${value} in zone ${zoneName}`);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2018-02-08 14:39:35 -08:00
|
|
|
dns.resolve(zoneName, 'NS', { timeout: 5000 }, function (error, nameservers) {
|
2018-04-29 11:20:12 -07:00
|
|
|
if (error || !nameservers) return retryCallback(error || new DomainsError(DomainsError.EXTERNAL_ERROR, 'Unable to get nameservers'));
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2018-02-08 14:19:14 -08:00
|
|
|
async.every(nameservers, isChangeSynced.bind(null, domain, value), function (error, synced) {
|
2018-02-08 14:55:06 -08:00
|
|
|
debug('waitForDns: %s %s ns: %j', domain, synced ? 'done' : 'not done', nameservers);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2018-04-29 11:20:12 -07:00
|
|
|
retryCallback(synced ? null : new DomainsError(DomainsError.EXTERNAL_ERROR, 'ETRYAGAIN'));
|
2015-12-11 13:14:27 -08:00
|
|
|
});
|
|
|
|
|
});
|
2016-04-22 16:01:19 -07:00
|
|
|
}, function retryDone(error) {
|
2018-01-09 16:09:47 -08:00
|
|
|
if (error) return callback(error);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
2018-02-08 14:55:06 -08:00
|
|
|
debug(`waitForDns: ${domain} has propagated`);
|
2015-12-11 13:14:27 -08:00
|
|
|
|
|
|
|
|
callback(null);
|
2018-01-09 16:09:47 -08:00
|
|
|
});
|
2015-12-11 13:14:27 -08:00
|
|
|
}
|