Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 11 additions & 13 deletions src/cares_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2332,16 +2332,16 @@ void SetLocalAddress(const FunctionCallbackInfo<Value>& args) {
// to 0 (any).

if (uv_inet_pton(AF_INET, *ip0, &addr0) == 0) {
ares_set_local_ip4(channel->cares_channel(), nbytes::ReadUint32BE(addr0));
type0 = 4;
} else if (uv_inet_pton(AF_INET6, *ip0, &addr0) == 0) {
ares_set_local_ip6(channel->cares_channel(), addr0);
type0 = 6;
} else {
THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP address.");
return;
}

// Validate the second argument before applying anything, so that a call
// that throws leaves the channel unchanged.
if (!args[1]->IsUndefined()) {
CHECK(args[1]->IsString());
node::Utf8Value ip1(isolate, args[1]);
Expand All @@ -2350,29 +2350,27 @@ void SetLocalAddress(const FunctionCallbackInfo<Value>& args) {
if (type0 == 4) {
THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv4 addresses.");
return;
} else {
ares_set_local_ip4(channel->cares_channel(),
nbytes::ReadUint32BE(addr1));
}
} else if (uv_inet_pton(AF_INET6, *ip1, &addr1) == 0) {
if (type0 == 6) {
THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv6 addresses.");
return;
} else {
ares_set_local_ip6(channel->cares_channel(), addr1);
}
} else {
THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP address.");
return;
}
} else {
// No second arg specified
if (type0 == 4) {
memset(&addr1, 0, sizeof(addr1));
ares_set_local_ip6(channel->cares_channel(), addr1);
} else {
ares_set_local_ip4(channel->cares_channel(), 0);
}
memset(&addr1, 0, sizeof(addr1));
}

if (type0 == 4) {
ares_set_local_ip4(channel->cares_channel(), nbytes::ReadUint32BE(addr0));
ares_set_local_ip6(channel->cares_channel(), addr1);
} else {
ares_set_local_ip6(channel->cares_channel(), addr0);
ares_set_local_ip4(channel->cares_channel(), nbytes::ReadUint32BE(addr1));
}
}

Expand Down
45 changes: 45 additions & 0 deletions test/parallel/test-dns-setlocaladdress-rejected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict';
const common = require('../common');

// Verifies that a call to resolver.setLocalAddress() that throws leaves the
// previously configured local address in place.

// Binding to 127.0.0.0/8 addresses other than 127.0.0.1 works out of the box
// on Linux only.
if (!common.isLinux)
common.skip('requires the whole 127.0.0.0/8 range on the loopback interface');

const assert = require('assert');
const dgram = require('dgram');
const { Resolver } = require('dns');

const resolver = new Resolver({ timeout: 1000, tries: 1 });
const server = dgram.createSocket('udp4');

server.on('message', common.mustCall((msg, rinfo) => {
assert.strictEqual(rinfo.address, '127.0.0.2');
server.close();
resolver.cancel();
}));

server.bind(0, '127.0.0.1', common.mustCall(() => {
resolver.setServers([`127.0.0.1:${server.address().port}`]);
resolver.setLocalAddress('127.0.0.2');

assert.throws(() => {
resolver.setLocalAddress('127.0.0.3', '127.0.0.4');
}, {
code: 'ERR_INVALID_ARG_VALUE',
message: 'Cannot specify two IPv4 addresses.',
});
assert.throws(() => {
resolver.setLocalAddress('127.0.0.5', 'bad');
}, {
code: 'ERR_INVALID_ARG_VALUE',
message: 'Invalid IP address.',
});

resolver.resolve4('example.test', common.mustCall((err) => {
assert.strictEqual(err.code, 'ECANCELLED');
}));
}));