From 0fd9638dc7fa1c6188eb0d207fd5f1ea03b746dd Mon Sep 17 00:00:00 2001 From: Daniel Turing Date: Mon, 8 Feb 2016 10:57:24 +0100 Subject: [PATCH] dns: add resolvePtr to query plain DNS PTR records Resolving plain PTR records is used beyond reverse DNS, most prominently with DNS-SD (RFC6763). This adds dns.resolvePtr(), and uses it (instead of dns.reverse()) in dns.resolve(). PR-URL: https://github.com/nodejs/node/pull/4921 Reviewed-By: Roman Reiss Reviewed-By: Brian White --- doc/api/dns.markdown | 8 ++++- lib/dns.js | 3 +- src/cares_wrap.cc | 44 +++++++++++++++++++++++++ test/internet/test-dns.js | 31 +++++++++++++++++ test/parallel/test-c-ares.js | 2 +- test/parallel/test-dns-cares-domains.js | 1 + 6 files changed, 86 insertions(+), 3 deletions(-) diff --git a/doc/api/dns.markdown b/doc/api/dns.markdown index 55c1314f9b550e..f986eadf7a7583 100644 --- a/doc/api/dns.markdown +++ b/doc/api/dns.markdown @@ -155,7 +155,7 @@ Valid values for `rrtype` are: * `'MX'` - mail exchange records * `'TXT'` - text records * `'SRV'` - SRV records - * `'PTR'` - used for reverse IP lookups + * `'PTR'` - PTR records * `'NS'` - name server records * `'CNAME'` - canonical name records * `'SOA'` - start of authority record @@ -248,6 +248,12 @@ be an array of objects with the following properties: } ``` +## dns.resolvePtr(hostname, callback) + +Uses the DNS protocol to resolve pointer records (`PTR` records) for the +`hostname`. The `addresses` argument passed to the `callback` function will +be an array of strings containing the reply records. + ## dns.resolveTxt(hostname, callback) Uses the DNS protocol to resolve text queries (`TXT` records) for the diff --git a/lib/dns.js b/lib/dns.js index bcf6aae626c594..04cc58755142ce 100644 --- a/lib/dns.js +++ b/lib/dns.js @@ -251,9 +251,10 @@ exports.resolveMx = resolveMap.MX = resolver('queryMx'); exports.resolveNs = resolveMap.NS = resolver('queryNs'); exports.resolveTxt = resolveMap.TXT = resolver('queryTxt'); exports.resolveSrv = resolveMap.SRV = resolver('querySrv'); +exports.resolvePtr = resolveMap.PTR = resolver('queryPtr'); exports.resolveNaptr = resolveMap.NAPTR = resolver('queryNaptr'); exports.resolveSoa = resolveMap.SOA = resolver('querySoa'); -exports.reverse = resolveMap.PTR = resolver('getHostByAddr'); +exports.reverse = resolver('getHostByAddr'); exports.resolve = function(hostname, type_, callback_) { diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 46636c528b7f81..0f5581b3f34638 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -698,6 +698,49 @@ class QuerySrvWrap: public QueryWrap { } }; +class QueryPtrWrap: public QueryWrap { + public: + explicit QueryPtrWrap(Environment* env, Local req_wrap_obj) + : QueryWrap(env, req_wrap_obj) { + } + + int Send(const char* name) override { + ares_query(env()->cares_channel(), + name, + ns_c_in, + ns_t_ptr, + Callback, + GetQueryArg()); + return 0; + } + + size_t self_size() const override { return sizeof(*this); } + + protected: + void Parse(unsigned char* buf, int len) override { + HandleScope handle_scope(env()->isolate()); + Context::Scope context_scope(env()->context()); + + struct hostent* host; + + int status = ares_parse_ptr_reply(buf, len, NULL, 0, AF_INET, &host); + if (status != ARES_SUCCESS) { + ParseError(status); + return; + } + + Local aliases = Array::New(env()->isolate()); + + for (uint32_t i = 0; host->h_aliases[i] != NULL; i++) { + aliases->Set(i, OneByteString(env()->isolate(), host->h_aliases[i])); + } + + ares_free_hostent(host); + + this->CallOnComplete(aliases); + } +}; + class QueryNaptrWrap: public QueryWrap { public: explicit QueryNaptrWrap(Environment* env, Local req_wrap_obj) @@ -1276,6 +1319,7 @@ static void Initialize(Local target, env->SetMethod(target, "queryNs", Query); env->SetMethod(target, "queryTxt", Query); env->SetMethod(target, "querySrv", Query); + env->SetMethod(target, "queryPtr", Query); env->SetMethod(target, "queryNaptr", Query); env->SetMethod(target, "querySoa", Query); env->SetMethod(target, "getHostByAddr", Query); diff --git a/test/internet/test-dns.js b/test/internet/test-dns.js index c448da4663de2c..aec66f5882ff5f 100644 --- a/test/internet/test-dns.js +++ b/test/internet/test-dns.js @@ -166,6 +166,37 @@ TEST(function test_resolveSrv_failure(done) { checkWrap(req); }); +TEST(function test_resolvePtr(done) { + var req = dns.resolvePtr('8.8.8.8.in-addr.arpa', function(err, result) { + if (err) throw err; + + assert.ok(result.length > 0); + + for (var i = 0; i < result.length; i++) { + var item = result[i]; + assert.ok(item); + assert.ok(typeof item === 'string'); + } + + done(); + }); + + checkWrap(req); +}); + +TEST(function test_resolvePtr_failure(done) { + var req = dns.resolvePtr('something.invalid', function(err, result) { + assert.ok(err instanceof Error); + assert.strictEqual(err.errno, 'ENOTFOUND'); + + assert.ok(result == undefined); + + done(); + }); + + checkWrap(req); +}); + TEST(function test_resolveNaptr(done) { var req = dns.resolveNaptr('sip2sip.info', function(err, result) { if (err) throw err; diff --git a/test/parallel/test-c-ares.js b/test/parallel/test-c-ares.js index b7802881f8e47c..8c2178ead6a93d 100644 --- a/test/parallel/test-c-ares.js +++ b/test/parallel/test-c-ares.js @@ -31,7 +31,7 @@ assert.throws(function() { // C:\Windows\System32\drivers\etc\hosts // so we disable this test on Windows. if (!common.isWindows) { - dns.resolve('127.0.0.1', 'PTR', function(error, domains) { + dns.reverse('127.0.0.1', function(error, domains) { if (error) throw error; assert.ok(Array.isArray(domains)); }); diff --git a/test/parallel/test-dns-cares-domains.js b/test/parallel/test-dns-cares-domains.js index a1aa18a10f88ec..76ebf0d628b1c4 100644 --- a/test/parallel/test-dns-cares-domains.js +++ b/test/parallel/test-dns-cares-domains.js @@ -12,6 +12,7 @@ var methods = [ 'resolveNs', 'resolveTxt', 'resolveSrv', + 'resolvePtr', 'resolveNaptr', 'resolveSoa' ];