GeezerVison is showing github.com — dns: make `dns.setServers` support customized port · nodejs/node@ebe7bb2
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/dns.md +30-6Lines changed: 30 additions & 6 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -59,8 +59,21 @@ the [Implementation considerations section][] for more information. | 59 | 59 | added: v0.11.3 | 60 | 60 | --> | 61 | 61 |
| 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 | +``` | 64 | 77 |
| 65 | 78 | ## dns.lookup(hostname[, options], callback) | 66 | 79 | <!-- YAML | @@ -436,12 +449,22 @@ one of the [DNS error codes][]. | 436 | 449 | <!-- YAML | 437 | 450 | added: v0.11.3 | 438 | 451 | --> | 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. | 440 | 457 |
| 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: | 443 | 459 |
| 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 | +``` | 445 | 468 |
| 446 | 469 | An error will be thrown if an invalid address is provided. | 447 | 470 |
| @@ -536,3 +559,4 @@ uses. For instance, _they do not use the configuration from `/etc/hosts`_. | 536 | 559 | [supported `getaddrinfo` flags]: #dns_supported_getaddrinfo_flags | 537 | 560 | [the official libuv documentation]: http://docs.libuv.org/en/latest/threadpool.html | 538 | 561 | [`util.promisify()`]: util.html#util_util_promisify_original | | 562 | +[rfc5952]: https://tools.ietf.org/html/rfc5952#section-6 |
Collapse file Copy file name to clipboardExpand all lines: lib/dns.js +20-8Lines changed: 20 additions & 8 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -60,6 +60,7 @@ function errnoException(err, syscall, hostname) { | 60 | 60 | return ex; | 61 | 61 | } | 62 | 62 |
| | 63 | +const IANA_DNS_PORT = 53; | 63 | 64 | const digits = [ | 64 | 65 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15 | 65 | 66 | 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_) { | 301 | 302 |
| 302 | 303 |
| 303 | 304 | 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 | + }); | 305 | 312 | } | 306 | 313 |
| 307 | 314 |
| @@ -311,26 +318,31 @@ function setServers(servers) { | 311 | 318 | const orig = cares.getServers(); | 312 | 319 | const newSet = []; | 313 | 320 | const IPv6RE = /\[(.*)\]/; | 314 | | - const addrSplitRE = /:\d+$/; | | 321 | + const addrSplitRE = /(^.+?)(?::(\d+))?$/; | 315 | 322 |
| 316 | 323 | servers.forEach((serv) => { | 317 | 324 | var ipVersion = isIP(serv); | 318 | 325 | if (ipVersion !== 0) | 319 | | - return newSet.push([ipVersion, serv]); | | 326 | + return newSet.push([ipVersion, serv, IANA_DNS_PORT]); | 320 | 327 |
| 321 | 328 | const match = serv.match(IPv6RE); | 322 | 329 | // we have an IPv6 in brackets | 323 | 330 | if (match) { | 324 | 331 | 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 | + } | 327 | 338 | } | 328 | 339 |
| 329 | | - const s = serv.split(addrSplitRE)[0]; | | 340 | + const [, s, p] = serv.match(addrSplitRE); | 330 | 341 | ipVersion = isIP(s); | 331 | 342 |
| 332 | | - if (ipVersion !== 0) | 333 | | - return newSet.push([ipVersion, s]); | | 343 | + if (ipVersion !== 0) { | | 344 | + return newSet.push([ipVersion, s, parseInt(p)]); | | 345 | + } | 334 | 346 |
| 335 | 347 | throw new Error(`IP address is not properly formatted: ${serv}`); | 336 | 348 | }); | |
Collapse file Copy file name to clipboardExpand all lines: src/cares_wrap.cc +20-12Lines changed: 20 additions & 12 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -419,9 +419,9 @@ void AresEnsureServers(Environment* env) { | 419 | 419 | } | 420 | 420 |
| 421 | 421 | ares_channel channel = env->cares_channel(); | 422 | | - ares_addr_node* servers = nullptr; | | 422 | + ares_addr_port_node* servers = nullptr; | 423 | 423 |
| 424 | | - ares_get_servers(channel, &servers); | | 424 | + ares_get_servers_ports(channel, &servers); | 425 | 425 |
| 426 | 426 | /* if no server or multi-servers, ignore */ | 427 | 427 | if (servers == nullptr) return; | @@ -433,7 +433,9 @@ void AresEnsureServers(Environment* env) { | 433 | 433 |
| 434 | 434 | /* if the only server is not 127.0.0.1, ignore */ | 435 | 435 | 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) { | 437 | 439 | ares_free_data(servers); | 438 | 440 | env->set_cares_is_servers_default(false); | 439 | 441 | return; | @@ -1384,12 +1386,12 @@ void GetServers(const FunctionCallbackInfo<Value>& args) { | 1384 | 1386 |
| 1385 | 1387 | Local<Array> server_array = Array::New(env->isolate()); | 1386 | 1388 |
| 1387 | | - ares_addr_node* servers; | | 1389 | + ares_addr_port_node* servers; | 1388 | 1390 |
| 1389 | | - int r = ares_get_servers(env->cares_channel(), &servers); | | 1391 | + int r = ares_get_servers_ports(env->cares_channel(), &servers); | 1390 | 1392 | CHECK_EQ(r, ARES_SUCCESS); | 1391 | 1393 |
| 1392 | | - ares_addr_node* cur = servers; | | 1394 | + ares_addr_port_node* cur = servers; | 1393 | 1395 |
| 1394 | 1396 | for (uint32_t i = 0; cur != nullptr; ++i, cur = cur->next) { | 1395 | 1397 | char ip[INET6_ADDRSTRLEN]; | @@ -1398,8 +1400,11 @@ void GetServers(const FunctionCallbackInfo<Value>& args) { | 1398 | 1400 | int err = uv_inet_ntop(cur->family, caddr, ip, sizeof(ip)); | 1399 | 1401 | CHECK_EQ(err, 0); | 1400 | 1402 |
| 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); | 1403 | 1408 | } | 1404 | 1409 |
| 1405 | 1410 | ares_free_data(servers); | @@ -1422,8 +1427,8 @@ void SetServers(const FunctionCallbackInfo<Value>& args) { | 1422 | 1427 | return args.GetReturnValue().Set(rv); | 1423 | 1428 | } | 1424 | 1429 |
| 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; | 1427 | 1432 |
| 1428 | 1433 | int err; | 1429 | 1434 |
| @@ -1434,12 +1439,15 @@ void SetServers(const FunctionCallbackInfo<Value>& args) { | 1434 | 1439 |
| 1435 | 1440 | CHECK(elm->Get(0)->Int32Value()); | 1436 | 1441 | CHECK(elm->Get(1)->IsString()); | | 1442 | + CHECK(elm->Get(2)->Int32Value()); | 1437 | 1443 |
| 1438 | 1444 | int fam = elm->Get(0)->Int32Value(); | 1439 | 1445 | node::Utf8Value ip(env->isolate(), elm->Get(1)); | | 1446 | + int port = elm->Get(2)->Int32Value(); | 1440 | 1447 |
| 1441 | | - ares_addr_node* cur = &servers[i]; | | 1448 | + ares_addr_port_node* cur = &servers[i]; | 1442 | 1449 |
| | 1450 | + cur->tcp_port = cur->udp_port = port; | 1443 | 1451 | switch (fam) { | 1444 | 1452 | case 4: | 1445 | 1453 | cur->family = AF_INET; | @@ -1465,7 +1473,7 @@ void SetServers(const FunctionCallbackInfo<Value>& args) { | 1465 | 1473 | } | 1466 | 1474 |
| 1467 | 1475 | if (err == 0) | 1468 | | - err = ares_set_servers(env->cares_channel(), &servers[0]); | | 1476 | + err = ares_set_servers_ports(env->cares_channel(), &servers[0]); | 1469 | 1477 | else | 1470 | 1478 | err = ARES_EBADSTR; | 1471 | 1479 |
| |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-dns.js +13Lines changed: 13 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -35,6 +35,8 @@ assert.doesNotThrow(() => { | 35 | 35 | servers[0] = '127.0.0.1'; | 36 | 36 | servers[2] = '0.0.0.0'; | 37 | 37 | dns.setServers(servers); | | 38 | + | | 39 | + assert.deepStrictEqual(dns.getServers(), ['127.0.0.1', '0.0.0.0']); | 38 | 40 | }); | 39 | 41 |
| 40 | 42 | assert.doesNotThrow(() => { | @@ -53,6 +55,11 @@ assert.doesNotThrow(() => { | 53 | 55 | }); | 54 | 56 |
| 55 | 57 | dns.setServers(servers); | | 58 | + assert.deepStrictEqual(dns.getServers(), [ | | 59 | + '127.0.0.1', | | 60 | + '192.168.1.1', | | 61 | + '0.0.0.0' | | 62 | + ]); | 56 | 63 | }); | 57 | 64 |
| 58 | 65 | const goog = [ | @@ -63,6 +70,8 @@ assert.doesNotThrow(() => dns.setServers(goog)); | 63 | 70 | assert.deepStrictEqual(dns.getServers(), goog); | 64 | 71 | assert.throws(() => dns.setServers(['foobar']), | 65 | 72 | /^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$/); | 66 | 75 | assert.deepStrictEqual(dns.getServers(), goog); | 67 | 76 |
| 68 | 77 | const goog6 = [ | @@ -79,10 +88,14 @@ assert.deepStrictEqual(dns.getServers(), goog6); | 79 | 88 | const ports = [ | 80 | 89 | '4.4.4.4:53', | 81 | 90 | '[2001:4860:4860::8888]:53', | | 91 | + '103.238.225.181:666', | | 92 | + '[fe80::483a:5aff:fee6:1f04]:666' | 82 | 93 | ]; | 83 | 94 | const portsExpected = [ | 84 | 95 | '4.4.4.4', | 85 | 96 | '2001:4860:4860::8888', | | 97 | + '103.238.225.181:666', | | 98 | + '[fe80::483a:5aff:fee6:1f04]:666' | 86 | 99 | ]; | 87 | 100 | dns.setServers(ports); | 88 | 101 | assert.deepStrictEqual(dns.getServers(), portsExpected); | |
|