Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support resolving plain DNS PTR records #4921

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion doc/api/dns.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,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
Expand Down Expand Up @@ -244,6 +244,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
Expand Down
3 changes: 2 additions & 1 deletion lib/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,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_) {
Expand Down
44 changes: 44 additions & 0 deletions src/cares_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,49 @@ class QuerySrvWrap: public QueryWrap {
}
};

class QueryPtrWrap: public QueryWrap {
public:
explicit QueryPtrWrap(Environment* env, Local<Object> 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<Array> 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<Object> req_wrap_obj)
Expand Down Expand Up @@ -1276,6 +1319,7 @@ static void Initialize(Local<Object> target,
env->SetMethod(target, "queryNs", Query<QueryNsWrap>);
env->SetMethod(target, "queryTxt", Query<QueryTxtWrap>);
env->SetMethod(target, "querySrv", Query<QuerySrvWrap>);
env->SetMethod(target, "queryPtr", Query<QueryPtrWrap>);
env->SetMethod(target, "queryNaptr", Query<QueryNaptrWrap>);
env->SetMethod(target, "querySoa", Query<QuerySoaWrap>);
env->SetMethod(target, "getHostByAddr", Query<GetHostByAddrWrap>);
Expand Down
120 changes: 120 additions & 0 deletions test/internet/test-dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ TEST(function test_resolveMx(done) {
checkWrap(req);
});

TEST(function test_resolveMx_failure(done) {
var req = dns.resolveMx('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_resolveNs(done) {
var req = dns.resolveNs('rackspace.com', function(err, names) {
Expand All @@ -103,6 +115,18 @@ TEST(function test_resolveNs(done) {
checkWrap(req);
});

TEST(function test_resolveNs_failure(done) {
var req = dns.resolveNs('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_resolveSrv(done) {
var req = dns.resolveSrv('_jabber._tcp.google.com', function(err, result) {
Expand All @@ -129,6 +153,50 @@ TEST(function test_resolveSrv(done) {
checkWrap(req);
});

TEST(function test_resolveSrv_failure(done) {
var req = dns.resolveSrv('something.invalid', function(err, result) {
assert.ok(err instanceof Error);
assert.strictEqual(err.errno, 'ENOTFOUND');

assert.ok(result == undefined);

done();
});

checkWrap(req);
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a IPv6 resolvePtr test too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, and possibly also one for dns.resolvePtr('8.8.8.8') which should result in an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your comments. I will add the requested tests next week.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@silverwind - i dont think a IPv6 resolvePtr test makes sense, PTRs actually don't deal with addresses.

I could resolve PTR for "8.8.8.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.6.8.4.0.6.8.4.1.0.0.2.ip6.arpa", Google's v6 reverse, but really the test_relovePtr uses "8.8.8.8.in-addr.arpa" only because it's a readily available PTR record - that it's a in-addr.arpa entry is just a coincidence.

dns.reverse(), which deals with addresses, is tested in test-dns-ipv6.js already.

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;
Expand All @@ -154,6 +222,19 @@ TEST(function test_resolveNaptr(done) {
checkWrap(req);
});

TEST(function test_resolveNaptr_failure(done) {
var req = dns.resolveNaptr('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_resolveSoa(done) {
var req = dns.resolveSoa('nodejs.org', function(err, result) {
if (err) throw err;
Expand Down Expand Up @@ -188,6 +269,19 @@ TEST(function test_resolveSoa(done) {
checkWrap(req);
});

TEST(function test_resolveSoa_failure(done) {
var req = dns.resolveSoa('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_resolveCname(done) {
var req = dns.resolveCname('www.microsoft.com', function(err, names) {
if (err) throw err;
Expand All @@ -206,6 +300,19 @@ TEST(function test_resolveCname(done) {
checkWrap(req);
});

TEST(function test_resolveCname_failure(done) {
var req = dns.resolveCname('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_resolveTxt(done) {
var req = dns.resolveTxt('google.com', function(err, records) {
Expand All @@ -219,6 +326,19 @@ TEST(function test_resolveTxt(done) {
checkWrap(req);
});

TEST(function test_resolveTxt_failure(done) {
var req = dns.resolveTxt('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_lookup_failure(done) {
var req = dns.lookup('does.not.exist', 4, function(err, ip, family) {
Expand Down
2 changes: 1 addition & 1 deletion test/parallel/test-c-ares.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
});
Expand Down
1 change: 1 addition & 0 deletions test/parallel/test-dns-cares-domains.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ var methods = [
'resolveNs',
'resolveTxt',
'resolveSrv',
'resolvePtr',
'resolveNaptr',
'resolveSoa'
];
Expand Down