Skip to content

Commit

Permalink
dns: make dns.setServers support customized port
Browse files Browse the repository at this point in the history
allow `dns.setServers` parameter to contain port

e.g.

```
dns.setServers([ '103.238.225.181:666' ]);
```

And `dns.getServers` will return IP with port if not the default port.

PR-URL: #13723
Refs: #7903
Reviewed-By: Refael Ackermann <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
  • Loading branch information
XadillaX authored and addaleax committed Jun 21, 2017
1 parent e03a056 commit 2bb6614
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 26 deletions.
36 changes: 30 additions & 6 deletions doc/api/dns.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -436,12 +449,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.

Expand Down Expand Up @@ -536,3 +559,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
28 changes: 20 additions & 8 deletions lib/dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -301,7 +302,13 @@ function resolve(hostname, type_, 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]}`;
});
}


Expand All @@ -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}`);
});
Expand Down
32 changes: 20 additions & 12 deletions src/cares_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -419,9 +419,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;
Expand All @@ -433,7 +433,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;
Expand Down Expand Up @@ -1384,12 +1386,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];
Expand All @@ -1398,8 +1400,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);
Expand All @@ -1422,8 +1427,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;

Expand All @@ -1434,12 +1439,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;
Expand All @@ -1465,7 +1473,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;

Expand Down
13 changes: 13 additions & 0 deletions test/parallel/test-dns.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(() => {
Expand All @@ -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 = [
Expand All @@ -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 = [
Expand All @@ -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);
Expand Down

0 comments on commit 2bb6614

Please sign in to comment.