From af9bad287d11a29e561b3ef1c48946d829bc7c22 Mon Sep 17 00:00:00 2001 From: Chance Hudson Date: Wed, 23 Jan 2019 19:42:08 -0600 Subject: [PATCH 1/5] Support _dnslink subdomain specified dnslinks --- src/core/runtime/dns-nodejs.js | 61 ++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/src/core/runtime/dns-nodejs.js b/src/core/runtime/dns-nodejs.js index 8f6bb132bd..d5c36d6930 100644 --- a/src/core/runtime/dns-nodejs.js +++ b/src/core/runtime/dns-nodejs.js @@ -3,19 +3,58 @@ const dns = require('dns') module.exports = (domain, opts, callback) => { - dns.resolveTxt(domain, (err, records) => { - if (err) { - return callback(err, null) - } + resolveDnslink(domain) + .catch(err => { + // If the code is not ENOTFOUND the throw the error + if (err.code !== 'ENOTFOUND') throw err - // TODO: implement recursive option - - for (const record of records) { - if (record[0].startsWith('dnslink=')) { - return callback(null, record[0].substr(8, record[0].length - 1)) + if (domain.indexOf('_dnslink') === -1) { + // Check the _dnslink subdomain + const _dnslinkDomain = ['_dnslink', ...domain.split('.')].join('.') + // If this throws then we propagate the error + return resolveDnslink(_dnslinkDomain) + } else if (domain.split('.').indexOf('_dnslink') === 0) { + // The supplied domain contains a _dnslink component + // Check the non-_dnslink domain + const rootDomain = domain.split('.').slice(1).join('.') + return resolveDnslink(rootDomain) } - } + throw err + }) + .then(dnslinkRecord => { + callback(null, dnslinkRecord.substr(8, dnslinkRecord.length - 1)) + }) + .catch(callback) +} - callback(new Error('domain does not have a txt dnslink entry')) +function resolveDnslink(domain) { + const DNSLINK_REGEX = /^dnslink=.+$/ + return new Promise((resolve, reject) => { + dns.resolveTxt(domain, (err, records) => { + if (err) return reject(err) + resolve(records) + }) }) + .then(records => { + // records is an array of arrays of strings + // the below expression flattens it into an array of strings + const flatRecords = [].concat(...records) + return flatRecords.filter(record => { + return DNSLINK_REGEX.test(record) + }) + }) + .then(dnslinkRecords => { + // we now have dns text entries as an array of strings + // only records passing the DNSLINK_REGEX text are included + if (dnslinkRecords > 1) { + const err = new Error(`Multiple dnslink records found for domain: ${domain}`) + err.code = 'EMULTFOUND' + throw err + } else if (dnslinkRecords.length === 0) { + const err = new Error(`No dnslink records found for domain: ${domain}`) + err.code = 'ENOTFOUND' + throw err + } + return dnslinkRecords[0] + }) } From b02c3d2c5616016f2d5eaf3d282f3c26eecc3a09 Mon Sep 17 00:00:00 2001 From: Chance Hudson Date: Wed, 23 Jan 2019 20:04:21 -0600 Subject: [PATCH 2/5] Add test for _dnslink subdomain --- src/core/runtime/dns-nodejs.js | 2 +- test/cli/dns.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/core/runtime/dns-nodejs.js b/src/core/runtime/dns-nodejs.js index d5c36d6930..9291370334 100644 --- a/src/core/runtime/dns-nodejs.js +++ b/src/core/runtime/dns-nodejs.js @@ -5,7 +5,7 @@ const dns = require('dns') module.exports = (domain, opts, callback) => { resolveDnslink(domain) .catch(err => { - // If the code is not ENOTFOUND the throw the error + // If the code is not ENOTFOUND then throw the error if (err.code !== 'ENOTFOUND') throw err if (domain.indexOf('_dnslink') === -1) { diff --git a/test/cli/dns.js b/test/cli/dns.js index 0c6ab4e1a5..55aea6f5b6 100644 --- a/test/cli/dns.js +++ b/test/cli/dns.js @@ -19,4 +19,12 @@ describe('dns', () => runOnAndOff((thing) => { expect(res.substr(0, 6)).to.eql('/ipns/') }) }) + + it('resolve _dnslink.ipfs.io dns', function () { + this.timeout(60 * 1000) + + return ipfs('dns _dnslink.ipfs.io').then((res) => { + expect(res.substr(0, 6)).to.eql('/ipns/') + }) + }) })) From 92ddb0405488fe793ff85a9e5a9eb7c9f37fcb9b Mon Sep 17 00:00:00 2001 From: Chance Hudson Date: Thu, 24 Jan 2019 05:26:11 -0600 Subject: [PATCH 3/5] Resolve comments --- src/core/runtime/dns-nodejs.js | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/core/runtime/dns-nodejs.js b/src/core/runtime/dns-nodejs.js index 9291370334..808a7e3d37 100644 --- a/src/core/runtime/dns-nodejs.js +++ b/src/core/runtime/dns-nodejs.js @@ -1,6 +1,7 @@ 'use strict' const dns = require('dns') +const _ = require('lodash'); module.exports = (domain, opts, callback) => { resolveDnslink(domain) @@ -8,49 +9,40 @@ module.exports = (domain, opts, callback) => { // If the code is not ENOTFOUND then throw the error if (err.code !== 'ENOTFOUND') throw err - if (domain.indexOf('_dnslink') === -1) { - // Check the _dnslink subdomain - const _dnslinkDomain = ['_dnslink', ...domain.split('.')].join('.') - // If this throws then we propagate the error - return resolveDnslink(_dnslinkDomain) - } else if (domain.split('.').indexOf('_dnslink') === 0) { + if (domain.startsWith('_dnslink.')) { // The supplied domain contains a _dnslink component // Check the non-_dnslink domain - const rootDomain = domain.split('.').slice(1).join('.') + const rootDomain = domain.replace('_dnslink.', '') return resolveDnslink(rootDomain) } - throw err + // Check the _dnslink subdomain + const _dnslinkDomain = `_dnslink.${domain}`; + // If this throws then we propagate the error + return resolveDnslink(_dnslinkDomain) }) .then(dnslinkRecord => { - callback(null, dnslinkRecord.substr(8, dnslinkRecord.length - 1)) + callback(null, dnslinkRecord.replace('dnslink=', '')) }) .catch(callback) } function resolveDnslink(domain) { const DNSLINK_REGEX = /^dnslink=.+$/ - return new Promise((resolve, reject) => { + return new Promise( (resolve, reject) => { dns.resolveTxt(domain, (err, records) => { if (err) return reject(err) resolve(records) }) }) .then(records => { - // records is an array of arrays of strings - // the below expression flattens it into an array of strings - const flatRecords = [].concat(...records) - return flatRecords.filter(record => { + return _.chain(records).flatten().filter(record => { return DNSLINK_REGEX.test(record) - }) + }).value() }) .then(dnslinkRecords => { // we now have dns text entries as an array of strings // only records passing the DNSLINK_REGEX text are included - if (dnslinkRecords > 1) { - const err = new Error(`Multiple dnslink records found for domain: ${domain}`) - err.code = 'EMULTFOUND' - throw err - } else if (dnslinkRecords.length === 0) { + if (dnslinkRecords.length === 0) { const err = new Error(`No dnslink records found for domain: ${domain}`) err.code = 'ENOTFOUND' throw err From 19a1b1e743f93863e1780788ffdb16cf674b801d Mon Sep 17 00:00:00 2001 From: Chance Hudson Date: Thu, 24 Jan 2019 05:27:20 -0600 Subject: [PATCH 4/5] Linter fixes --- src/core/runtime/dns-nodejs.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/runtime/dns-nodejs.js b/src/core/runtime/dns-nodejs.js index 808a7e3d37..f5d5b71dd1 100644 --- a/src/core/runtime/dns-nodejs.js +++ b/src/core/runtime/dns-nodejs.js @@ -1,7 +1,7 @@ 'use strict' const dns = require('dns') -const _ = require('lodash'); +const _ = require('lodash') module.exports = (domain, opts, callback) => { resolveDnslink(domain) @@ -16,7 +16,7 @@ module.exports = (domain, opts, callback) => { return resolveDnslink(rootDomain) } // Check the _dnslink subdomain - const _dnslinkDomain = `_dnslink.${domain}`; + const _dnslinkDomain = `_dnslink.${domain}` // If this throws then we propagate the error return resolveDnslink(_dnslinkDomain) }) @@ -26,9 +26,9 @@ module.exports = (domain, opts, callback) => { .catch(callback) } -function resolveDnslink(domain) { +function resolveDnslink (domain) { const DNSLINK_REGEX = /^dnslink=.+$/ - return new Promise( (resolve, reject) => { + return new Promise((resolve, reject) => { dns.resolveTxt(domain, (err, records) => { if (err) return reject(err) resolve(records) From 1e09adde4a697176f01566dbda83a7593b2aed6b Mon Sep 17 00:00:00 2001 From: Chance Hudson Date: Thu, 24 Jan 2019 08:29:43 -0600 Subject: [PATCH 5/5] Use err-code for dnslink record not found error --- src/core/runtime/dns-nodejs.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/core/runtime/dns-nodejs.js b/src/core/runtime/dns-nodejs.js index f5d5b71dd1..a3d583ef92 100644 --- a/src/core/runtime/dns-nodejs.js +++ b/src/core/runtime/dns-nodejs.js @@ -2,12 +2,13 @@ const dns = require('dns') const _ = require('lodash') +const errcode = require('err-code') module.exports = (domain, opts, callback) => { resolveDnslink(domain) .catch(err => { - // If the code is not ENOTFOUND then throw the error - if (err.code !== 'ENOTFOUND') throw err + // If the code is not ENOTFOUND or ERR_DNSLINK_NOT_FOUND then throw the error + if (err.code !== 'ENOTFOUND' && err.code !== 'ERR_DNSLINK_NOT_FOUND') throw err if (domain.startsWith('_dnslink.')) { // The supplied domain contains a _dnslink component @@ -43,9 +44,7 @@ function resolveDnslink (domain) { // we now have dns text entries as an array of strings // only records passing the DNSLINK_REGEX text are included if (dnslinkRecords.length === 0) { - const err = new Error(`No dnslink records found for domain: ${domain}`) - err.code = 'ENOTFOUND' - throw err + throw errcode(`No dnslink records found for domain: ${domain}`, 'ERR_DNSLINK_NOT_FOUND') } return dnslinkRecords[0] })