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.
|
||||
- `all` {boolean} When `true`, the callback returns all resolved addresses in
|
||||
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}
|
||||
- `err` {Error}
|
||||
- `address` {string} A string representation of an IPv4 or IPv6 address.
|
||||
|
@ -131,6 +131,7 @@ function lookup(hostname, options, callback) {
|
||||
var hints = 0;
|
||||
var family = -1;
|
||||
var all = false;
|
||||
var verbatim = false;
|
||||
|
||||
// Parse arguments
|
||||
if (hostname && typeof hostname !== 'string') {
|
||||
@ -145,6 +146,7 @@ function lookup(hostname, options, callback) {
|
||||
hints = options.hints >>> 0;
|
||||
family = options.family >>> 0;
|
||||
all = options.all === true;
|
||||
verbatim = options.verbatim === true;
|
||||
|
||||
if (hints !== 0 &&
|
||||
hints !== cares.AI_ADDRCONFIG &&
|
||||
@ -185,7 +187,7 @@ function lookup(hostname, options, callback) {
|
||||
req.hostname = hostname;
|
||||
req.oncomplete = all ? onlookupall : onlookup;
|
||||
|
||||
var err = cares.getaddrinfo(req, hostname, family, hints);
|
||||
var err = cares.getaddrinfo(req, hostname, family, hints, verbatim);
|
||||
if (err) {
|
||||
process.nextTick(callback, errnoException(err, 'getaddrinfo', hostname));
|
||||
return {};
|
||||
|
@ -196,15 +196,23 @@ void ChannelWrap::New(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
class GetAddrInfoReqWrap : public ReqWrap<uv_getaddrinfo_t> {
|
||||
public:
|
||||
GetAddrInfoReqWrap(Environment* env, Local<Object> req_wrap_obj);
|
||||
GetAddrInfoReqWrap(Environment* env,
|
||||
Local<Object> req_wrap_obj,
|
||||
bool verbatim);
|
||||
~GetAddrInfoReqWrap();
|
||||
|
||||
size_t self_size() const override { return sizeof(*this); }
|
||||
bool verbatim() const { return verbatim_; }
|
||||
|
||||
private:
|
||||
const bool verbatim_;
|
||||
};
|
||||
|
||||
GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env,
|
||||
Local<Object> req_wrap_obj)
|
||||
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP) {
|
||||
Local<Object> req_wrap_obj,
|
||||
bool verbatim)
|
||||
: ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP)
|
||||
, verbatim_(verbatim) {
|
||||
Wrap(req_wrap_obj, this);
|
||||
}
|
||||
|
||||
@ -1811,70 +1819,38 @@ void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
|
||||
};
|
||||
|
||||
if (status == 0) {
|
||||
// Success
|
||||
struct addrinfo *address;
|
||||
int n = 0;
|
||||
|
||||
// Create the response array.
|
||||
Local<Array> results = Array::New(env->isolate());
|
||||
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
const char *addr;
|
||||
auto add = [&] (bool want_ipv4, bool want_ipv6) {
|
||||
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
|
||||
// strings for each IP and filling the results array.
|
||||
address = res;
|
||||
while (address) {
|
||||
CHECK_EQ(address->ai_socktype, SOCK_STREAM);
|
||||
const char* addr;
|
||||
if (want_ipv4 && p->ai_family == AF_INET) {
|
||||
addr = reinterpret_cast<char*>(
|
||||
&(reinterpret_cast<struct sockaddr_in*>(p->ai_addr)->sin_addr));
|
||||
} 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.
|
||||
if (address->ai_family == AF_INET) {
|
||||
// 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)
|
||||
char ip[INET6_ADDRSTRLEN];
|
||||
if (uv_inet_ntop(p->ai_family, addr, ip, sizeof(ip)))
|
||||
continue;
|
||||
|
||||
// Create JavaScript string
|
||||
Local<String> s = OneByteString(env->isolate(), ip);
|
||||
results->Set(n, s);
|
||||
n++;
|
||||
}
|
||||
};
|
||||
|
||||
// Increment
|
||||
address = address->ai_next;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
const bool verbatim = req_wrap->verbatim();
|
||||
add(true, verbatim);
|
||||
if (verbatim == false)
|
||||
add(false, true);
|
||||
|
||||
// No responses were found to return
|
||||
if (n == 0) {
|
||||
@ -1965,6 +1941,7 @@ void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK(args[0]->IsObject());
|
||||
CHECK(args[1]->IsString());
|
||||
CHECK(args[2]->IsInt32());
|
||||
CHECK(args[4]->IsBoolean());
|
||||
Local<Object> req_wrap_obj = args[0].As<Object>();
|
||||
node::Utf8Value hostname(env->isolate(), args[1]);
|
||||
|
||||
@ -1985,7 +1962,7 @@ void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
|
||||
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;
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
|
@ -553,7 +553,7 @@ console.log('looking up nodejs.org...');
|
||||
|
||||
const cares = process.binding('cares_wrap');
|
||||
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) {
|
||||
assert.strictEqual(err, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user