initial ipv6 support

this adds and waits for AAAA records based on setting. we have to wait
for both A and AAAA because we don't know if the user is accessing via
IPv4 or IPv6. For Let's Encrypt, IPv6 is preferred (but not sure if it
retries if IPv6 is unreachable).

part of #264
This commit is contained in:
Girish Ramakrishnan
2022-01-06 17:02:16 -08:00
parent 7d7539f931
commit d65ac353fe
6 changed files with 82 additions and 32 deletions
+15 -7
View File
@@ -15,6 +15,7 @@ const assert = require('assert'),
debug = require('debug')('box:dns/manual'),
dns = require('../dns.js'),
safe = require('safetydance'),
settings = require('../settings.js'),
sysinfo = require('../sysinfo.js'),
waitForDns = require('./waitfordns.js');
@@ -75,7 +76,6 @@ async function verifyDomainConfig(domainObject) {
const zoneName = domainObject.zoneName;
// Very basic check if the nameservers can be fetched
const [error, nameservers] = await safe(dns.promises.resolve(zoneName, 'NS', { timeout: 5000 }));
if (error && error.code === 'ENOTFOUND') throw new BoxError(BoxError.BAD_FIELD, 'Unable to resolve nameservers for this domain', { field: 'nameservers' });
if (error || !nameservers) throw new BoxError(BoxError.BAD_FIELD, error ? error.message : 'Unable to get nameservers', { field: 'nameservers' });
@@ -83,14 +83,22 @@ async function verifyDomainConfig(domainObject) {
const location = 'cloudrontestdns';
const fqdn = dns.fqdn(location, domainObject);
const [error2, result] = await safe(dns.promises.resolve(fqdn, 'A', { server: '127.0.0.1', timeout: 5000 }));
if (error2 && error2.code === 'ENOTFOUND') throw new BoxError(BoxError.BAD_FIELD, `Unable to resolve ${fqdn}`, { field: 'nameservers' });
if (error2 || !result) throw new BoxError(BoxError.BAD_FIELD, error2 ? error2.message : `Unable to resolve ${fqdn}`, { field: 'nameservers' });
const [ipv4Error, ipv4Result] = await safe(dns.promises.resolve(fqdn, 'A', { server: '127.0.0.1', timeout: 5000 }));
if (ipv4Error && ipv4Error.code === 'ENOTFOUND') throw new BoxError(BoxError.BAD_FIELD, `Unable to resolve IPv4 of ${fqdn}`, { field: 'nameservers' });
if (ipv4Error || !ipv4Result) throw new BoxError(BoxError.BAD_FIELD, ipv4Error ? ipv4Error.message : `Unable to resolve IPv4 of ${fqdn}`, { field: 'nameservers' });
const [error3, ip] = await safe(sysinfo.getServerIPv4());
if (error3) throw new BoxError(BoxError.EXTERNAL_ERROR, `Failed to detect IP of this server: ${error3.message}`);
const ipv4 = await sysinfo.getServerIPv4();
if (ipv4Result.length !== 1 || ipv4 !== ipv4Result[0]) throw new BoxError(BoxError.EXTERNAL_ERROR, `Domain resolves to ${JSON.stringify(ipv4Result)} instead of IPv4 ${ipv4}`);
if (result.length !== 1 || ip !== result[0]) throw new BoxError(BoxError.EXTERNAL_ERROR, `Domain resolves to ${JSON.stringify(result)} instead of ${ip}`);
const ipv6Enabled = await settings.getIPv6Config();
if (ipv6Enabled) {
const [ipv6Error, ipv6Result] = await safe(dns.promises.resolve(fqdn, 'AAAA', { server: '127.0.0.1', timeout: 5000 }));
if (ipv6Error && ipv6Error.code === 'ENOTFOUND') throw new BoxError(BoxError.BAD_FIELD, `Unable to resolve IPv6 of ${fqdn}`, { field: 'nameservers' });
if (ipv6Error || !ipv6Result) throw new BoxError(BoxError.BAD_FIELD, ipv6Error ? ipv6Error.message : `Unable to resolve IPv6 of ${fqdn}`, { field: 'nameservers' });
const ipv6 = await sysinfo.getServerIPv6(); // both should be RFC 5952 format
if (ipv6Result.length !== 1 || ipv6 !== ipv6Result[0]) throw new BoxError(BoxError.EXTERNAL_ERROR, `Domain resolves to ${JSON.stringify(ipv6Result)} instead of IPv6 ${ipv6}`);
}
return {};
}