Skip to content

Commit ebe7bb2

Browse files
XadillaXaddaleax
authored andcommitted
dns: make dns.setServers support customized port
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]>
1 parent 683f743 commit ebe7bb2

File tree

4 files changed

+83
-26
lines changed

4 files changed

+83
-26
lines changed

doc/api/dns.md

+30-6
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,21 @@ the [Implementation considerations section][] for more information.
5959
added: v0.11.3
6060
-->
6161

62-
Returns an array of IP address strings that are being used for name
63-
resolution.
62+
Returns an array of IP address strings, formatted according to [rfc5952][],
63+
that are currently configured for DNS resolution. A string will include a port
64+
section if a custom port is used.
65+
66+
For example:
67+
68+
<!-- eslint-disable -->
69+
```js
70+
[
71+
'4.4.4.4',
72+
'2001:4860:4860::8888',
73+
'4.4.4.4:1053',
74+
'[2001:4860:4860::8888]:1053'
75+
]
76+
```
6477

6578
## dns.lookup(hostname[, options], callback)
6679
<!-- YAML
@@ -436,12 +449,22 @@ one of the [DNS error codes][].
436449
<!-- YAML
437450
added: v0.11.3
438451
-->
439-
- `servers` {string[]}
452+
- `servers` {string[]} array of [rfc5952][] formatted addresses
453+
454+
Sets the IP address and port of servers to be used when performing DNS
455+
resolution. The `servers` argument is an array of [rfc5952][] formatted
456+
addresses. If the port is the IANA default DNS port (53) it can be omitted.
440457

441-
Sets the IP addresses of the servers to be used when resolving. The `servers`
442-
argument is an array of IPv4 or IPv6 addresses.
458+
For example:
443459

444-
If a port is specified on the address, it will be removed.
460+
```js
461+
dns.setServers([
462+
'4.4.4.4',
463+
'[2001:4860:4860::8888]',
464+
'4.4.4.4:1053',
465+
'[2001:4860:4860::8888]:1053'
466+
]);
467+
```
445468

446469
An error will be thrown if an invalid address is provided.
447470

@@ -536,3 +559,4 @@ uses. For instance, _they do not use the configuration from `/etc/hosts`_.
536559
[supported `getaddrinfo` flags]: #dns_supported_getaddrinfo_flags
537560
[the official libuv documentation]: http://docs.libuv.org/en/latest/threadpool.html
538561
[`util.promisify()`]: util.html#util_util_promisify_original
562+
[rfc5952]: https://tools.ietf.org/html/rfc5952#section-6

lib/dns.js

+20-8
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ function errnoException(err, syscall, hostname) {
6060
return ex;
6161
}
6262

63+
const IANA_DNS_PORT = 53;
6364
const digits = [
6465
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15
6566
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, type_, callback_) {
301302

302303

303304
function getServers() {
304-
return cares.getServers();
305+
const ret = cares.getServers();
306+
return ret.map((val) => {
307+
if (!val[1] || val[1] === IANA_DNS_PORT) return val[0];
308+
309+
const host = isIP(val[0]) === 6 ? `[${val[0]}]` : val[0];
310+
return `${host}:${val[1]}`;
311+
});
305312
}
306313

307314

@@ -311,26 +318,31 @@ function setServers(servers) {
311318
const orig = cares.getServers();
312319
const newSet = [];
313320
const IPv6RE = /\[(.*)\]/;
314-
const addrSplitRE = /:\d+$/;
321+
const addrSplitRE = /(^.+?)(?::(\d+))?$/;
315322

316323
servers.forEach((serv) => {
317324
var ipVersion = isIP(serv);
318325
if (ipVersion !== 0)
319-
return newSet.push([ipVersion, serv]);
326+
return newSet.push([ipVersion, serv, IANA_DNS_PORT]);
320327

321328
const match = serv.match(IPv6RE);
322329
// we have an IPv6 in brackets
323330
if (match) {
324331
ipVersion = isIP(match[1]);
325-
if (ipVersion !== 0)
326-
return newSet.push([ipVersion, match[1]]);
332+
if (ipVersion !== 0) {
333+
const port =
334+
parseInt(serv.replace(addrSplitRE, '$2')) ||
335+
IANA_DNS_PORT;
336+
return newSet.push([ipVersion, match[1], port]);
337+
}
327338
}
328339

329-
const s = serv.split(addrSplitRE)[0];
340+
const [, s, p] = serv.match(addrSplitRE);
330341
ipVersion = isIP(s);
331342

332-
if (ipVersion !== 0)
333-
return newSet.push([ipVersion, s]);
343+
if (ipVersion !== 0) {
344+
return newSet.push([ipVersion, s, parseInt(p)]);
345+
}
334346

335347
throw new Error(`IP address is not properly formatted: ${serv}`);
336348
});

src/cares_wrap.cc

+20-12
Original file line numberDiff line numberDiff line change
@@ -419,9 +419,9 @@ void AresEnsureServers(Environment* env) {
419419
}
420420

421421
ares_channel channel = env->cares_channel();
422-
ares_addr_node* servers = nullptr;
422+
ares_addr_port_node* servers = nullptr;
423423

424-
ares_get_servers(channel, &servers);
424+
ares_get_servers_ports(channel, &servers);
425425

426426
/* if no server or multi-servers, ignore */
427427
if (servers == nullptr) return;
@@ -433,7 +433,9 @@ void AresEnsureServers(Environment* env) {
433433

434434
/* if the only server is not 127.0.0.1, ignore */
435435
if (servers[0].family != AF_INET ||
436-
servers[0].addr.addr4.s_addr != htonl(INADDR_LOOPBACK)) {
436+
servers[0].addr.addr4.s_addr != htonl(INADDR_LOOPBACK) ||
437+
servers[0].tcp_port != 0 ||
438+
servers[0].udp_port != 0) {
437439
ares_free_data(servers);
438440
env->set_cares_is_servers_default(false);
439441
return;
@@ -1384,12 +1386,12 @@ void GetServers(const FunctionCallbackInfo<Value>& args) {
13841386

13851387
Local<Array> server_array = Array::New(env->isolate());
13861388

1387-
ares_addr_node* servers;
1389+
ares_addr_port_node* servers;
13881390

1389-
int r = ares_get_servers(env->cares_channel(), &servers);
1391+
int r = ares_get_servers_ports(env->cares_channel(), &servers);
13901392
CHECK_EQ(r, ARES_SUCCESS);
13911393

1392-
ares_addr_node* cur = servers;
1394+
ares_addr_port_node* cur = servers;
13931395

13941396
for (uint32_t i = 0; cur != nullptr; ++i, cur = cur->next) {
13951397
char ip[INET6_ADDRSTRLEN];
@@ -1398,8 +1400,11 @@ void GetServers(const FunctionCallbackInfo<Value>& args) {
13981400
int err = uv_inet_ntop(cur->family, caddr, ip, sizeof(ip));
13991401
CHECK_EQ(err, 0);
14001402

1401-
Local<String> addr = OneByteString(env->isolate(), ip);
1402-
server_array->Set(i, addr);
1403+
Local<Array> ret = Array::New(env->isolate(), 2);
1404+
ret->Set(0, OneByteString(env->isolate(), ip));
1405+
ret->Set(1, Integer::New(env->isolate(), cur->udp_port));
1406+
1407+
server_array->Set(i, ret);
14031408
}
14041409

14051410
ares_free_data(servers);
@@ -1422,8 +1427,8 @@ void SetServers(const FunctionCallbackInfo<Value>& args) {
14221427
return args.GetReturnValue().Set(rv);
14231428
}
14241429

1425-
ares_addr_node* servers = new ares_addr_node[len];
1426-
ares_addr_node* last = nullptr;
1430+
ares_addr_port_node* servers = new ares_addr_port_node[len];
1431+
ares_addr_port_node* last = nullptr;
14271432

14281433
int err;
14291434

@@ -1434,12 +1439,15 @@ void SetServers(const FunctionCallbackInfo<Value>& args) {
14341439

14351440
CHECK(elm->Get(0)->Int32Value());
14361441
CHECK(elm->Get(1)->IsString());
1442+
CHECK(elm->Get(2)->Int32Value());
14371443

14381444
int fam = elm->Get(0)->Int32Value();
14391445
node::Utf8Value ip(env->isolate(), elm->Get(1));
1446+
int port = elm->Get(2)->Int32Value();
14401447

1441-
ares_addr_node* cur = &servers[i];
1448+
ares_addr_port_node* cur = &servers[i];
14421449

1450+
cur->tcp_port = cur->udp_port = port;
14431451
switch (fam) {
14441452
case 4:
14451453
cur->family = AF_INET;
@@ -1465,7 +1473,7 @@ void SetServers(const FunctionCallbackInfo<Value>& args) {
14651473
}
14661474

14671475
if (err == 0)
1468-
err = ares_set_servers(env->cares_channel(), &servers[0]);
1476+
err = ares_set_servers_ports(env->cares_channel(), &servers[0]);
14691477
else
14701478
err = ARES_EBADSTR;
14711479

test/parallel/test-dns.js

+13
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ assert.doesNotThrow(() => {
3535
servers[0] = '127.0.0.1';
3636
servers[2] = '0.0.0.0';
3737
dns.setServers(servers);
38+
39+
assert.deepStrictEqual(dns.getServers(), ['127.0.0.1', '0.0.0.0']);
3840
});
3941

4042
assert.doesNotThrow(() => {
@@ -53,6 +55,11 @@ assert.doesNotThrow(() => {
5355
});
5456

5557
dns.setServers(servers);
58+
assert.deepStrictEqual(dns.getServers(), [
59+
'127.0.0.1',
60+
'192.168.1.1',
61+
'0.0.0.0'
62+
]);
5663
});
5764

5865
const goog = [
@@ -63,6 +70,8 @@ assert.doesNotThrow(() => dns.setServers(goog));
6370
assert.deepStrictEqual(dns.getServers(), goog);
6471
assert.throws(() => dns.setServers(['foobar']),
6572
/^Error: IP address is not properly formatted: foobar$/);
73+
assert.throws(() => dns.setServers(['127.0.0.1:va']),
74+
/^Error: IP address is not properly formatted: 127\.0\.0\.1:va$/);
6675
assert.deepStrictEqual(dns.getServers(), goog);
6776

6877
const goog6 = [
@@ -79,10 +88,14 @@ assert.deepStrictEqual(dns.getServers(), goog6);
7988
const ports = [
8089
'4.4.4.4:53',
8190
'[2001:4860:4860::8888]:53',
91+
'103.238.225.181:666',
92+
'[fe80::483a:5aff:fee6:1f04]:666'
8293
];
8394
const portsExpected = [
8495
'4.4.4.4',
8596
'2001:4860:4860::8888',
97+
'103.238.225.181:666',
98+
'[fe80::483a:5aff:fee6:1f04]:666'
8699
];
87100
dns.setServers(ports);
88101
assert.deepStrictEqual(dns.getServers(), portsExpected);

0 commit comments

Comments
 (0)