summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/api/dns.md36
-rw-r--r--lib/dns.js28
-rw-r--r--src/cares_wrap.cc32
-rw-r--r--test/parallel/test-dns.js13
4 files changed, 83 insertions, 26 deletions
diff --git a/doc/api/dns.md b/doc/api/dns.md
index 94e64864b6..3813712305 100644
--- a/doc/api/dns.md
+++ b/doc/api/dns.md
@@ -59,8 +59,21 @@ the [Implementation considerations section][] for more information.
added: v0.11.3
-->
-Returns an array of IP address strings that are being used for name
-resolution.
+Returns an array of IP address strings, formatted according to [rfc5952][],
+that are currently configured for DNS resolution. A string will include a port
+section if a custom port is used.
+
+For example:
+
+<!-- eslint-disable -->
+```js
+[
+ '4.4.4.4',
+ '2001:4860:4860::8888',
+ '4.4.4.4:1053',
+ '[2001:4860:4860::8888]:1053'
+]
+```
## dns.lookup(hostname[, options], callback)
<!-- YAML
@@ -482,12 +495,22 @@ one of the [DNS error codes][].
<!-- YAML
added: v0.11.3
-->
-- `servers` {string[]}
+- `servers` {string[]} array of [rfc5952][] formatted addresses
+
+Sets the IP address and port of servers to be used when performing DNS
+resolution. The `servers` argument is an array of [rfc5952][] formatted
+addresses. If the port is the IANA default DNS port (53) it can be omitted.
-Sets the IP addresses of the servers to be used when resolving. The `servers`
-argument is an array of IPv4 or IPv6 addresses.
+For example:
-If a port is specified on the address, it will be removed.
+```js
+dns.setServers([
+ '4.4.4.4',
+ '[2001:4860:4860::8888]',
+ '4.4.4.4:1053',
+ '[2001:4860:4860::8888]:1053'
+]);
+```
An error will be thrown if an invalid address is provided.
@@ -583,3 +606,4 @@ uses. For instance, _they do not use the configuration from `/etc/hosts`_.
[supported `getaddrinfo` flags]: #dns_supported_getaddrinfo_flags
[the official libuv documentation]: http://docs.libuv.org/en/latest/threadpool.html
[`util.promisify()`]: util.html#util_util_promisify_original
+[rfc5952]: https://tools.ietf.org/html/rfc5952#section-6
diff --git a/lib/dns.js b/lib/dns.js
index e2af27863e..8f84a07950 100644
--- a/lib/dns.js
+++ b/lib/dns.js
@@ -60,6 +60,7 @@ function errnoException(err, syscall, hostname) {
return ex;
}
+const IANA_DNS_PORT = 53;
const digits = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
@@ -301,7 +302,13 @@ function resolve(hostname, rrtype, callback) {
function getServers() {
- return cares.getServers();
+ const ret = cares.getServers();
+ return ret.map((val) => {
+ if (!val[1] || val[1] === IANA_DNS_PORT) return val[0];
+
+ const host = isIP(val[0]) === 6 ? `[${val[0]}]` : val[0];
+ return `${host}:${val[1]}`;
+ });
}
@@ -311,26 +318,31 @@ function setServers(servers) {
const orig = cares.getServers();
const newSet = [];
const IPv6RE = /\[(.*)\]/;
- const addrSplitRE = /:\d+$/;
+ const addrSplitRE = /(^.+?)(?::(\d+))?$/;
servers.forEach((serv) => {
var ipVersion = isIP(serv);
if (ipVersion !== 0)
- return newSet.push([ipVersion, serv]);
+ return newSet.push([ipVersion, serv, IANA_DNS_PORT]);
const match = serv.match(IPv6RE);
// we have an IPv6 in brackets
if (match) {
ipVersion = isIP(match[1]);
- if (ipVersion !== 0)
- return newSet.push([ipVersion, match[1]]);
+ if (ipVersion !== 0) {
+ const port =
+ parseInt(serv.replace(addrSplitRE, '$2')) ||
+ IANA_DNS_PORT;
+ return newSet.push([ipVersion, match[1], port]);
+ }
}
- const s = serv.split(addrSplitRE)[0];
+ const [, s, p] = serv.match(addrSplitRE);
ipVersion = isIP(s);
- if (ipVersion !== 0)
- return newSet.push([ipVersion, s]);
+ if (ipVersion !== 0) {
+ return newSet.push([ipVersion, s, parseInt(p)]);
+ }
throw new Error(`IP address is not properly formatted: ${serv}`);
});
diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc
index bd340f0d92..41a5633ee0 100644
--- a/src/cares_wrap.cc
+++ b/src/cares_wrap.cc
@@ -442,9 +442,9 @@ void AresEnsureServers(Environment* env) {
}
ares_channel channel = env->cares_channel();
- ares_addr_node* servers = nullptr;
+ ares_addr_port_node* servers = nullptr;
- ares_get_servers(channel, &servers);
+ ares_get_servers_ports(channel, &servers);
/* if no server or multi-servers, ignore */
if (servers == nullptr) return;
@@ -456,7 +456,9 @@ void AresEnsureServers(Environment* env) {
/* if the only server is not 127.0.0.1, ignore */
if (servers[0].family != AF_INET ||
- servers[0].addr.addr4.s_addr != htonl(INADDR_LOOPBACK)) {
+ servers[0].addr.addr4.s_addr != htonl(INADDR_LOOPBACK) ||
+ servers[0].tcp_port != 0 ||
+ servers[0].udp_port != 0) {
ares_free_data(servers);
env->set_cares_is_servers_default(false);
return;
@@ -1924,12 +1926,12 @@ void GetServers(const FunctionCallbackInfo<Value>& args) {
Local<Array> server_array = Array::New(env->isolate());
- ares_addr_node* servers;
+ ares_addr_port_node* servers;
- int r = ares_get_servers(env->cares_channel(), &servers);
+ int r = ares_get_servers_ports(env->cares_channel(), &servers);
CHECK_EQ(r, ARES_SUCCESS);
- ares_addr_node* cur = servers;
+ ares_addr_port_node* cur = servers;
for (uint32_t i = 0; cur != nullptr; ++i, cur = cur->next) {
char ip[INET6_ADDRSTRLEN];
@@ -1938,8 +1940,11 @@ void GetServers(const FunctionCallbackInfo<Value>& args) {
int err = uv_inet_ntop(cur->family, caddr, ip, sizeof(ip));
CHECK_EQ(err, 0);
- Local<String> addr = OneByteString(env->isolate(), ip);
- server_array->Set(i, addr);
+ Local<Array> ret = Array::New(env->isolate(), 2);
+ ret->Set(0, OneByteString(env->isolate(), ip));
+ ret->Set(1, Integer::New(env->isolate(), cur->udp_port));
+
+ server_array->Set(i, ret);
}
ares_free_data(servers);
@@ -1962,8 +1967,8 @@ void SetServers(const FunctionCallbackInfo<Value>& args) {
return args.GetReturnValue().Set(rv);
}
- ares_addr_node* servers = new ares_addr_node[len];
- ares_addr_node* last = nullptr;
+ ares_addr_port_node* servers = new ares_addr_port_node[len];
+ ares_addr_port_node* last = nullptr;
int err;
@@ -1974,12 +1979,15 @@ void SetServers(const FunctionCallbackInfo<Value>& args) {
CHECK(elm->Get(0)->Int32Value());
CHECK(elm->Get(1)->IsString());
+ CHECK(elm->Get(2)->Int32Value());
int fam = elm->Get(0)->Int32Value();
node::Utf8Value ip(env->isolate(), elm->Get(1));
+ int port = elm->Get(2)->Int32Value();
- ares_addr_node* cur = &servers[i];
+ ares_addr_port_node* cur = &servers[i];
+ cur->tcp_port = cur->udp_port = port;
switch (fam) {
case 4:
cur->family = AF_INET;
@@ -2005,7 +2013,7 @@ void SetServers(const FunctionCallbackInfo<Value>& args) {
}
if (err == 0)
- err = ares_set_servers(env->cares_channel(), &servers[0]);
+ err = ares_set_servers_ports(env->cares_channel(), &servers[0]);
else
err = ARES_EBADSTR;
diff --git a/test/parallel/test-dns.js b/test/parallel/test-dns.js
index a605e76c1d..175ac10298 100644
--- a/test/parallel/test-dns.js
+++ b/test/parallel/test-dns.js
@@ -35,6 +35,8 @@ assert.doesNotThrow(() => {
servers[0] = '127.0.0.1';
servers[2] = '0.0.0.0';
dns.setServers(servers);
+
+ assert.deepStrictEqual(dns.getServers(), ['127.0.0.1', '0.0.0.0']);
});
assert.doesNotThrow(() => {
@@ -53,6 +55,11 @@ assert.doesNotThrow(() => {
});
dns.setServers(servers);
+ assert.deepStrictEqual(dns.getServers(), [
+ '127.0.0.1',
+ '192.168.1.1',
+ '0.0.0.0'
+ ]);
});
const goog = [
@@ -63,6 +70,8 @@ assert.doesNotThrow(() => dns.setServers(goog));
assert.deepStrictEqual(dns.getServers(), goog);
assert.throws(() => dns.setServers(['foobar']),
/^Error: IP address is not properly formatted: foobar$/);
+assert.throws(() => dns.setServers(['127.0.0.1:va']),
+ /^Error: IP address is not properly formatted: 127\.0\.0\.1:va$/);
assert.deepStrictEqual(dns.getServers(), goog);
const goog6 = [
@@ -79,10 +88,14 @@ assert.deepStrictEqual(dns.getServers(), goog6);
const ports = [
'4.4.4.4:53',
'[2001:4860:4860::8888]:53',
+ '103.238.225.181:666',
+ '[fe80::483a:5aff:fee6:1f04]:666'
];
const portsExpected = [
'4.4.4.4',
'2001:4860:4860::8888',
+ '103.238.225.181:666',
+ '[fe80::483a:5aff:fee6:1f04]:666'
];
dns.setServers(ports);
assert.deepStrictEqual(dns.getServers(), portsExpected);