Skip to content

Commit 13577d4

Browse files
bnoordhuisMylesBorins
authored andcommitted
dns: add verbatim option to dns.lookup()
When true, results from the DNS resolver are passed on as-is, without the reshuffling that Node.js otherwise does that puts IPv4 addresses before IPv6 addresses. PR-URL: #14731 Ref: #6307 Reviewed-By: Refael Ackermann <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 3d9ad82 commit 13577d4

File tree

4 files changed

+43
-58
lines changed

4 files changed

+43
-58
lines changed

doc/api/dns.md

+6
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ changes:
140140
flags may be passed by bitwise `OR`ing their values.
141141
- `all` {boolean} When `true`, the callback returns all resolved addresses in
142142
an array. Otherwise, returns a single address. Defaults to `false`.
143+
- `verbatim` {boolean} When `true`, the callback receives IPv4 and IPv6
144+
addresses in the order the DNS resolver returned them. When `false`,
145+
IPv4 addresses are placed before IPv6 addresses.
146+
Default: currently `false` (addresses are reordered) but this is expected
147+
to change in the not too distant future.
148+
New code should use `{ verbatim: true }`.
143149
- `callback` {Function}
144150
- `err` {Error}
145151
- `address` {string} A string representation of an IPv4 or IPv6 address.

lib/dns.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ function lookup(hostname, options, callback) {
126126
var hints = 0;
127127
var family = -1;
128128
var all = false;
129+
var verbatim = false;
129130

130131
// Parse arguments
131132
if (hostname && typeof hostname !== 'string') {
@@ -140,6 +141,7 @@ function lookup(hostname, options, callback) {
140141
hints = options.hints >>> 0;
141142
family = options.family >>> 0;
142143
all = options.all === true;
144+
verbatim = options.verbatim === true;
143145

144146
if (hints !== 0 &&
145147
hints !== cares.AI_ADDRCONFIG &&
@@ -180,7 +182,7 @@ function lookup(hostname, options, callback) {
180182
req.hostname = hostname;
181183
req.oncomplete = all ? onlookupall : onlookup;
182184

183-
var err = cares.getaddrinfo(req, hostname, family, hints);
185+
var err = cares.getaddrinfo(req, hostname, family, hints, verbatim);
184186
if (err) {
185187
process.nextTick(callback, errnoException(err, 'getaddrinfo', hostname));
186188
return {};

src/cares_wrap.cc

+33-56
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,23 @@ void ChannelWrap::New(const FunctionCallbackInfo<Value>& args) {
196196

197197
class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> {
198198
public:
199-
GetAddrInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);
199+
GetAddrInfoReqWrap(Environment* env,
200+
Local<Object> req_wrap_obj,
201+
bool verbatim);
200202
~GetAddrInfoReqWrap();
201203

202204
size_t self_size() const override { return sizeof(*this); }
205+
bool verbatim() const { return verbatim_; }
206+
207+
private:
208+
const bool verbatim_;
203209
};
204210

205211
GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env,
206-
Local<Object> req_wrap_obj)
207-
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP) {
212+
Local<Object> req_wrap_obj,
213+
bool verbatim)
214+
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP)
215+
, verbatim_(verbatim) {
208216
Wrap(req_wrap_obj, this);
209217
}
210218

@@ -1811,70 +1819,38 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
18111819
};
18121820

18131821
if (status == 0) {
1814-
// Success
1815-
struct addrinfo *address;
18161822
int n = 0;
1817-
1818-
// Create the response array.
18191823
Local<Array> results = Array::New(env->isolate());
18201824

1821-
char ip[INET6_ADDRSTRLEN];
1822-
const char *addr;
1823-
1824-
// Iterate over the IPv4 responses again this time creating javascript
1825-
// strings for each IP and filling the results array.
1826-
address = res;
1827-
while (address) {
1828-
CHECK_EQ(address->ai_socktype, SOCK_STREAM);
1829-
1830-
// Ignore random ai_family types.
1831-
if (address->ai_family == AF_INET) {
1832-
// Juggle pointers
1833-
addr = reinterpret_cast<char*>(&(reinterpret_cast<struct sockaddr_in*>(
1834-
address->ai_addr)->sin_addr));
1835-
int err = uv_inet_ntop(address->ai_family,
1836-
addr,
1837-
ip,
1838-
INET6_ADDRSTRLEN);
1839-
if (err)
1825+
auto add = [&] (bool want_ipv4, bool want_ipv6) {
1826+
for (auto p = res; p != nullptr; p = p->ai_next) {
1827+
CHECK_EQ(p->ai_socktype, SOCK_STREAM);
1828+
1829+
const char* addr;
1830+
if (want_ipv4 && p->ai_family == AF_INET) {
1831+
addr = reinterpret_cast<char*>(
1832+
&(reinterpret_cast<struct sockaddr_in*>(p->ai_addr)->sin_addr));
1833+
} else if (want_ipv6 && p->ai_family == AF_INET6) {
1834+
addr = reinterpret_cast<char*>(
1835+
&(reinterpret_cast<struct sockaddr_in6*>(p->ai_addr)->sin6_addr));
1836+
} else {
18401837
continue;
1838+
}
18411839

1842-
// Create JavaScript string
1843-
Local<String> s = OneByteString(env->isolate(), ip);
1844-
results->Set(n, s);
1845-
n++;
1846-
}
1847-
1848-
// Increment
1849-
address = address->ai_next;
1850-
}
1851-
1852-
// Iterate over the IPv6 responses putting them in the array.
1853-
address = res;
1854-
while (address) {
1855-
CHECK_EQ(address->ai_socktype, SOCK_STREAM);
1856-
1857-
// Ignore random ai_family types.
1858-
if (address->ai_family == AF_INET6) {
1859-
// Juggle pointers
1860-
addr = reinterpret_cast<char*>(&(reinterpret_cast<struct sockaddr_in6*>(
1861-
address->ai_addr)->sin6_addr));
1862-
int err = uv_inet_ntop(address->ai_family,
1863-
addr,
1864-
ip,
1865-
INET6_ADDRSTRLEN);
1866-
if (err)
1840+
char ip[INET6_ADDRSTRLEN];
1841+
if (uv_inet_ntop(p->ai_family, addr, ip, sizeof(ip)))
18671842
continue;
18681843

1869-
// Create JavaScript string
18701844
Local<String> s = OneByteString(env->isolate(), ip);
18711845
results->Set(n, s);
18721846
n++;
18731847
}
1848+
};
18741849

1875-
// Increment
1876-
address = address->ai_next;
1877-
}
1850+
const bool verbatim = req_wrap->verbatim();
1851+
add(true, verbatim);
1852+
if (verbatim == false)
1853+
add(false, true);
18781854

18791855
// No responses were found to return
18801856
if (n == 0) {
@@ -1965,6 +1941,7 @@ void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
19651941
CHECK(args[0]->IsObject());
19661942
CHECK(args[1]->IsString());
19671943
CHECK(args[2]->IsInt32());
1944+
CHECK(args[4]->IsBoolean());
19681945
Local<Object> req_wrap_obj = args[0].As<Object>();
19691946
node::Utf8Value hostname(env->isolate(), args[1]);
19701947

@@ -1985,7 +1962,7 @@ void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
19851962
CHECK(0 && "bad address family");
19861963
}
19871964

1988-
GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap(env, req_wrap_obj);
1965+
auto req_wrap = new GetAddrInfoReqWrap(env, req_wrap_obj, args[4]->IsTrue());
19891966

19901967
struct addrinfo hints;
19911968
memset(&hints, 0, sizeof(struct addrinfo));

test/internet/test-dns.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ console.log('looking up nodejs.org...');
549549

550550
const cares = process.binding('cares_wrap');
551551
const req = new cares.GetAddrInfoReqWrap();
552-
cares.getaddrinfo(req, 'nodejs.org', 4);
552+
cares.getaddrinfo(req, 'nodejs.org', 4, /* hints */ 0, /* verbatim */ true);
553553

554554
req.oncomplete = function(err, domains) {
555555
assert.strictEqual(err, 0);

0 commit comments

Comments
 (0)