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: https://github.com/nodejs/node/pull/14731 Ref: https://github.com/nodejs/node/issues/6307 Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
cbd3708c85
commit
e007f66ae2
@ -140,6 +140,12 @@ changes:
|
|||||||
flags may be passed by bitwise `OR`ing their values.
|
flags may be passed by bitwise `OR`ing their values.
|
||||||
- `all` {boolean} When `true`, the callback returns all resolved addresses in
|
- `all` {boolean} When `true`, the callback returns all resolved addresses in
|
||||||
an array. Otherwise, returns a single address. Defaults to `false`.
|
an array. Otherwise, returns a single address. Defaults to `false`.
|
||||||
|
- `verbatim` {boolean} When `true`, the callback receives IPv4 and IPv6
|
||||||
|
addresses in the order the DNS resolver returned them. When `false`,
|
||||||
|
IPv4 addresses are placed before IPv6 addresses.
|
||||||
|
Default: currently `false` (addresses are reordered) but this is expected
|
||||||
|
to change in the not too distant future.
|
||||||
|
New code should use `{ verbatim: true }`.
|
||||||
- `callback` {Function}
|
- `callback` {Function}
|
||||||
- `err` {Error}
|
- `err` {Error}
|
||||||
- `address` {string} A string representation of an IPv4 or IPv6 address.
|
- `address` {string} A string representation of an IPv4 or IPv6 address.
|
||||||
|
@ -131,6 +131,7 @@ function lookup(hostname, options, callback) {
|
|||||||
var hints = 0;
|
var hints = 0;
|
||||||
var family = -1;
|
var family = -1;
|
||||||
var all = false;
|
var all = false;
|
||||||
|
var verbatim = false;
|
||||||
|
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
if (hostname && typeof hostname !== 'string') {
|
if (hostname && typeof hostname !== 'string') {
|
||||||
@ -145,6 +146,7 @@ function lookup(hostname, options, callback) {
|
|||||||
hints = options.hints >>> 0;
|
hints = options.hints >>> 0;
|
||||||
family = options.family >>> 0;
|
family = options.family >>> 0;
|
||||||
all = options.all === true;
|
all = options.all === true;
|
||||||
|
verbatim = options.verbatim === true;
|
||||||
|
|
||||||
if (hints !== 0 &&
|
if (hints !== 0 &&
|
||||||
hints !== cares.AI_ADDRCONFIG &&
|
hints !== cares.AI_ADDRCONFIG &&
|
||||||
@ -185,7 +187,7 @@ function lookup(hostname, options, callback) {
|
|||||||
req.hostname = hostname;
|
req.hostname = hostname;
|
||||||
req.oncomplete = all ? onlookupall : onlookup;
|
req.oncomplete = all ? onlookupall : onlookup;
|
||||||
|
|
||||||
var err = cares.getaddrinfo(req, hostname, family, hints);
|
var err = cares.getaddrinfo(req, hostname, family, hints, verbatim);
|
||||||
if (err) {
|
if (err) {
|
||||||
process.nextTick(callback, errnoException(err, 'getaddrinfo', hostname));
|
process.nextTick(callback, errnoException(err, 'getaddrinfo', hostname));
|
||||||
return {};
|
return {};
|
||||||
|
@ -196,15 +196,23 @@ void ChannelWrap::New(const FunctionCallbackInfo<Value>& args) {
|
|||||||
|
|
||||||
class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> {
|
class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> {
|
||||||
public:
|
public:
|
||||||
GetAddrInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);
|
GetAddrInfoReqWrap(Environment* env,
|
||||||
|
Local<Object> req_wrap_obj,
|
||||||
|
bool verbatim);
|
||||||
~GetAddrInfoReqWrap();
|
~GetAddrInfoReqWrap();
|
||||||
|
|
||||||
size_t self_size() const override { return sizeof(*this); }
|
size_t self_size() const override { return sizeof(*this); }
|
||||||
|
bool verbatim() const { return verbatim_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const bool verbatim_;
|
||||||
};
|
};
|
||||||
|
|
||||||
GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env,
|
GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env,
|
||||||
Local<Object> req_wrap_obj)
|
Local<Object> req_wrap_obj,
|
||||||
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP) {
|
bool verbatim)
|
||||||
|
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP)
|
||||||
|
, verbatim_(verbatim) {
|
||||||
Wrap(req_wrap_obj, this);
|
Wrap(req_wrap_obj, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1811,70 +1819,38 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
// Success
|
|
||||||
struct addrinfo *address;
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
// Create the response array.
|
|
||||||
Local<Array> results = Array::New(env->isolate());
|
Local<Array> results = Array::New(env->isolate());
|
||||||
|
|
||||||
char ip[INET6_ADDRSTRLEN];
|
auto add = [&] (bool want_ipv4, bool want_ipv6) {
|
||||||
const char *addr;
|
for (auto p = res; p != nullptr; p = p->ai_next) {
|
||||||
|
CHECK_EQ(p->ai_socktype, SOCK_STREAM);
|
||||||
|
|
||||||
// Iterate over the IPv4 responses again this time creating javascript
|
const char* addr;
|
||||||
// strings for each IP and filling the results array.
|
if (want_ipv4 && p->ai_family == AF_INET) {
|
||||||
address = res;
|
addr = reinterpret_cast<char*>(
|
||||||
while (address) {
|
&(reinterpret_cast<struct sockaddr_in*>(p->ai_addr)->sin_addr));
|
||||||
CHECK_EQ(address->ai_socktype, SOCK_STREAM);
|
} else if (want_ipv6 && p->ai_family == AF_INET6) {
|
||||||
|
addr = reinterpret_cast<char*>(
|
||||||
|
&(reinterpret_cast<struct sockaddr_in6*>(p->ai_addr)->sin6_addr));
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore random ai_family types.
|
char ip[INET6_ADDRSTRLEN];
|
||||||
if (address->ai_family == AF_INET) {
|
if (uv_inet_ntop(p->ai_family, addr, ip, sizeof(ip)))
|
||||||
// Juggle pointers
|
|
||||||
addr = reinterpret_cast<char*>(&(reinterpret_cast<struct sockaddr_in*>(
|
|
||||||
address->ai_addr)->sin_addr));
|
|
||||||
int err = uv_inet_ntop(address->ai_family,
|
|
||||||
addr,
|
|
||||||
ip,
|
|
||||||
INET6_ADDRSTRLEN);
|
|
||||||
if (err)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Create JavaScript string
|
|
||||||
Local<String> s = OneByteString(env->isolate(), ip);
|
Local<String> s = OneByteString(env->isolate(), ip);
|
||||||
results->Set(n, s);
|
results->Set(n, s);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Increment
|
const bool verbatim = req_wrap->verbatim();
|
||||||
address = address->ai_next;
|
add(true, verbatim);
|
||||||
}
|
if (verbatim == false)
|
||||||
|
add(false, true);
|
||||||
// Iterate over the IPv6 responses putting them in the array.
|
|
||||||
address = res;
|
|
||||||
while (address) {
|
|
||||||
CHECK_EQ(address->ai_socktype, SOCK_STREAM);
|
|
||||||
|
|
||||||
// Ignore random ai_family types.
|
|
||||||
if (address->ai_family == AF_INET6) {
|
|
||||||
// Juggle pointers
|
|
||||||
addr = reinterpret_cast<char*>(&(reinterpret_cast<struct sockaddr_in6*>(
|
|
||||||
address->ai_addr)->sin6_addr));
|
|
||||||
int err = uv_inet_ntop(address->ai_family,
|
|
||||||
addr,
|
|
||||||
ip,
|
|
||||||
INET6_ADDRSTRLEN);
|
|
||||||
if (err)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Create JavaScript string
|
|
||||||
Local<String> s = OneByteString(env->isolate(), ip);
|
|
||||||
results->Set(n, s);
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment
|
|
||||||
address = address->ai_next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No responses were found to return
|
// No responses were found to return
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
@ -1965,6 +1941,7 @@ void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
|
|||||||
CHECK(args[0]->IsObject());
|
CHECK(args[0]->IsObject());
|
||||||
CHECK(args[1]->IsString());
|
CHECK(args[1]->IsString());
|
||||||
CHECK(args[2]->IsInt32());
|
CHECK(args[2]->IsInt32());
|
||||||
|
CHECK(args[4]->IsBoolean());
|
||||||
Local<Object> req_wrap_obj = args[0].As<Object>();
|
Local<Object> req_wrap_obj = args[0].As<Object>();
|
||||||
node::Utf8Value hostname(env->isolate(), args[1]);
|
node::Utf8Value hostname(env->isolate(), args[1]);
|
||||||
|
|
||||||
@ -1985,7 +1962,7 @@ void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
|
|||||||
CHECK(0 && "bad address family");
|
CHECK(0 && "bad address family");
|
||||||
}
|
}
|
||||||
|
|
||||||
GetAddrInfoReqWrap* req_wrap = new GetAddrInfoReqWrap(env, req_wrap_obj);
|
auto req_wrap = new GetAddrInfoReqWrap(env, req_wrap_obj, args[4]->IsTrue());
|
||||||
|
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
memset(&hints, 0, sizeof(struct addrinfo));
|
memset(&hints, 0, sizeof(struct addrinfo));
|
||||||
|
@ -553,7 +553,7 @@ console.log('looking up nodejs.org...');
|
|||||||
|
|
||||||
const cares = process.binding('cares_wrap');
|
const cares = process.binding('cares_wrap');
|
||||||
const req = new cares.GetAddrInfoReqWrap();
|
const req = new cares.GetAddrInfoReqWrap();
|
||||||
cares.getaddrinfo(req, 'nodejs.org', 4);
|
cares.getaddrinfo(req, 'nodejs.org', 4, /* hints */ 0, /* verbatim */ true);
|
||||||
|
|
||||||
req.oncomplete = function(err, domains) {
|
req.oncomplete = function(err, domains) {
|
||||||
assert.strictEqual(err, 0);
|
assert.strictEqual(err, 0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user