Skip to content

Commit

Permalink
dns: allow dns.lookup() to return all addresses
Browse files Browse the repository at this point in the history
This commit adds the 'all' option to dns.lookup(), allowing
all lookup results to be returned.

Semver: Minor
Fixes: #736
PR-URL: #744
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Ben Noordhuis <[email protected]>
  • Loading branch information
silverwind authored and cjihrig committed Feb 6, 2015
1 parent 1cd1d7a commit 633a990
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 27 deletions.
36 changes: 22 additions & 14 deletions doc/api/dns.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -61,29 +61,37 @@ AAAA (IPv6) record. `options` can be an object or integer. If `options` is
not provided, then IP v4 and v6 addresses are both valid. If `options` is
an integer, then it must be `4` or `6`.

Alternatively, `options` can be an object containing two properties,
`family` and `hints`. Both properties are optional. If `family` is provided,
it must be the integer `4` or `6`. If `family` is not provided then IP v4
and v6 addresses are accepted. The `hints` field, if present, should be one
or more of the supported `getaddrinfo` flags. If `hints` is not provided,
then no flags are passed to `getaddrinfo`. Multiple flags can be passed
through `hints` by logically `OR`ing their values. An example usage of
`options` is shown below.
Alternatively, `options` can be an object containing these properties:

* `family` {Number} - The record family. If present, must be the integer
`4` or `6`. If not provided, both IP v4 and v6 addresses are accepted.
* `hints`: {Number} - If present, it should be one or more of the supported
`getaddrinfo` flags. If `hints` is not provided, then no flags are passed to
`getaddrinfo`. Multiple flags can be passed through `hints` by logically
`OR`ing their values.
See [supported `getaddrinfo` flags](#dns_supported_getaddrinfo_flags) below
for more information on supported flags.
* `all`: {Boolean} - When `true`, the callback returns all resolved addresses
in an array, otherwise returns a single address. Defaults to `false`.

All properties are optional. An example usage of options is shown below.

```
{
family: 4,
hints: dns.ADDRCONFIG | dns.V4MAPPED
all: true
}
```

See [supported `getaddrinfo` flags](#dns_supported_getaddrinfo_flags) below for
more information on supported flags.
The callback has arguments `(err, address, family)`. `address` is a string
representation of a IP v4 or v6 address. `family` is either the integer 4 or 6
and denotes the family of `address` (not necessarily the value initially passed
to `lookup`).

The callback has arguments `(err, address, family)`. The `address` argument
is a string representation of a IP v4 or v6 address. The `family` argument
is either the integer 4 or 6 and denotes the family of `address` (not
necessarily the value initially passed to `lookup`).
With the `all` option set, the arguments change to `(err, addresses)`, with
`addresses` being an array of objects with the properties `address` and
`family`.

On error, `err` is an `Error` object, where `err.code` is the error code.
Keep in mind that `err.code` will be set to `'ENOENT'` not only when
Expand Down
33 changes: 30 additions & 3 deletions lib/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,29 @@ function onlookup(err, addresses) {
}


function onlookupall(err, addresses) {
var results = [];
if (err) {
return this.callback(errnoException(err, 'getaddrinfo', this.hostname));
}

for (var i = 0; i < addresses.length; i++) {
results.push({
address: addresses[i],
family: this.family || (addresses[i].indexOf(':') >= 0 ? 6 : 4)
});
}

this.callback(null, results);
}


// Easy DNS A/AAAA look up
// lookup(hostname, [options,] callback)
exports.lookup = function lookup(hostname, options, callback) {
var hints = 0;
var family = -1;
var all = false;

// Parse arguments
if (hostname && typeof hostname !== 'string') {
Expand All @@ -99,6 +117,7 @@ exports.lookup = function lookup(hostname, options, callback) {
} else if (options !== null && typeof options === 'object') {
hints = options.hints >>> 0;
family = options.family >>> 0;
all = options.all === true;

if (hints !== 0 &&
hints !== exports.ADDRCONFIG &&
Expand All @@ -121,21 +140,29 @@ exports.lookup = function lookup(hostname, options, callback) {
callback = makeAsync(callback);

if (!hostname) {
callback(null, null, family === 6 ? 6 : 4);
if (all) {
callback(null, []);
} else {
callback(null, null, family === 6 ? 6 : 4);
}
return {};
}

var matchedFamily = net.isIP(hostname);
if (matchedFamily) {
callback(null, hostname, matchedFamily);
if (all) {
callback(null, [{address: hostname, family: matchedFamily}]);
} else {
callback(null, hostname, matchedFamily);
}
return {};
}

var req = new GetAddrInfoReqWrap();
req.callback = callback;
req.family = family;
req.hostname = hostname;
req.oncomplete = onlookup;
req.oncomplete = all ? onlookupall : onlookup;

var err = cares.getaddrinfo(req, hostname, family, hints);
if (err) {
Expand Down
106 changes: 96 additions & 10 deletions test/internet/test-dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,34 +226,34 @@ TEST(function test_resolveNaptr(done) {
TEST(function test_resolveSoa(done) {
var req = dns.resolveSoa('nodejs.org', function(err, result) {
if (err) throw err;

assert.ok(result);
assert.ok(typeof result === 'object');

assert.ok(typeof result.nsname === 'string');
assert.ok(result.nsname.length > 0);

assert.ok(typeof result.hostmaster === 'string');
assert.ok(result.hostmaster.length > 0);

assert.ok(typeof result.serial === 'number');
assert.ok((result.serial > 0) && (result.serial < 4294967295));

assert.ok(typeof result.refresh === 'number');
assert.ok((result.refresh > 0) && (result.refresh < 2147483647));
assert.ok((result.refresh > 0) && (result.refresh < 2147483647));

assert.ok(typeof result.retry === 'number');
assert.ok((result.retry > 0) && (result.retry < 2147483647));

assert.ok(typeof result.expire === 'number');
assert.ok((result.expire > 0) && (result.expire < 2147483647));

assert.ok(typeof result.minttl === 'number');
assert.ok((result.minttl >= 0) && (result.minttl < 2147483647));

done();
});

checkWrap(req);
});

Expand Down Expand Up @@ -471,6 +471,92 @@ TEST(function test_lookup_localhost_ipv4(done) {
});


TEST(function test_lookup_ip_all(done) {
var req = dns.lookup('127.0.0.1', {all: true}, function(err, ips, family) {
if (err) throw err;
assert.ok(Array.isArray(ips));
assert.ok(ips.length > 0);
assert.strictEqual(ips[0].address, '127.0.0.1');
assert.strictEqual(ips[0].family, 4);

done();
});

checkWrap(req);
});


TEST(function test_lookup_null_all(done) {
var req = dns.lookup(null, {all: true}, function(err, ips, family) {
if (err) throw err;
assert.ok(Array.isArray(ips));
assert.strictEqual(ips.length, 0);

done();
});

checkWrap(req);
});


TEST(function test_lookup_all_ipv4(done) {
var req = dns.lookup('www.google.com', {all: true, family: 4}, function(err, ips) {
if (err) throw err;
assert.ok(Array.isArray(ips));
assert.ok(ips.length > 0);

ips.forEach(function(ip) {
assert.ok(isIPv4(ip.address));
assert.strictEqual(ip.family, 4);
});

done();
});

checkWrap(req);
});


TEST(function test_lookup_all_ipv6(done) {
var req = dns.lookup('www.google.com', {all: true, family: 6}, function(err, ips) {
if (err) throw err;
assert.ok(Array.isArray(ips));
assert.ok(ips.length > 0);

ips.forEach(function(ip) {
assert.ok(isIPv6(ip.address));
assert.strictEqual(ip.family, 6);
});

done();
});

checkWrap(req);
});


TEST(function test_lookup_all_mixed(done) {
var req = dns.lookup('www.google.com', {all: true}, function(err, ips) {
if (err) throw err;
assert.ok(Array.isArray(ips));
assert.ok(ips.length > 0);

ips.forEach(function(ip) {
if (isIPv4(ip.address))
assert.equal(ip.family, 4);
else if (isIPv6(ip.address))
assert.equal(ip.family, 6);
else
assert(false);
});

done();
});

checkWrap(req);
});


TEST(function test_lookupservice_ip_ipv4(done) {
var req = dns.lookupService('127.0.0.1', 80, function(err, host, service) {
if (err) throw err;
Expand Down

0 comments on commit 633a990

Please sign in to comment.