Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 548f91a

Browse filesBrowse files
daguejtargos
authored andcommitted
dns: add setLocalAddress to Resolver
Fixes: #34818 PR-URL: #34824 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Roman Reiss <me@silverwind.io>
1 parent cfe61b8 commit 548f91a
Copy full SHA for 548f91a

File tree

Expand file treeCollapse file tree

5 files changed

+137
-0
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

5 files changed

+137
-0
lines changed
Open diff view settings
Collapse file

‎doc/api/dns.md‎

Copy file name to clipboardExpand all lines: doc/api/dns.md
+21Lines changed: 21 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,27 @@ added: v8.3.0
117117
Cancel all outstanding DNS queries made by this resolver. The corresponding
118118
callbacks will be called with an error with code `ECANCELLED`.
119119

120+
### `resolver.setLocalAddress([ipv4][, ipv6])`
121+
<!-- YAML
122+
added: REPLACEME
123+
-->
124+
125+
* `ipv4` {string} A string representation of an IPv4 address.
126+
**Default:** `'0.0.0.0'`
127+
* `ipv6` {string} A string representation of an IPv6 address.
128+
**Default:** `'::0'`
129+
130+
The resolver instance will send its requests from the specified IP address.
131+
This allows programs to specify outbound interfaces when used on multi-homed
132+
systems.
133+
134+
If a v4 or v6 address is not specified, it is set to the default, and the
135+
operating system will choose a local address automatically.
136+
137+
The resolver will use the v4 local address when making requests to IPv4 DNS
138+
servers, and the v6 local address when making requests to IPv6 DNS servers.
139+
The `rrtype` of resolution requests has no impact on the local address used.
140+
120141
## `dns.getServers()`
121142
<!-- YAML
122143
added: v0.11.3
Collapse file

‎lib/internal/dns/promises.js‎

Copy file name to clipboardExpand all lines: lib/internal/dns/promises.js
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ class Resolver {
217217

218218
Resolver.prototype.getServers = CallbackResolver.prototype.getServers;
219219
Resolver.prototype.setServers = CallbackResolver.prototype.setServers;
220+
Resolver.prototype.setLocalAddress = CallbackResolver.prototype.setLocalAddress;
220221
Resolver.prototype.resolveAny = resolveMap.ANY = resolver('queryAny');
221222
Resolver.prototype.resolve4 = resolveMap.A = resolver('queryA');
222223
Resolver.prototype.resolve6 = resolveMap.AAAA = resolver('queryAaaa');
Collapse file

‎lib/internal/dns/utils.js‎

Copy file name to clipboardExpand all lines: lib/internal/dns/utils.js
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ class Resolver {
114114
throw new ERR_DNS_SET_SERVERS_FAILED(err, servers);
115115
}
116116
}
117+
118+
setLocalAddress(ipv4, ipv6) {
119+
if (typeof ipv4 !== 'string') {
120+
throw new ERR_INVALID_ARG_TYPE('ipv4', 'String', ipv4);
121+
}
122+
123+
if (typeof ipv6 !== 'string' && ipv6 !== undefined) {
124+
throw new ERR_INVALID_ARG_TYPE('ipv6', ['String', 'undefined'], ipv6);
125+
}
126+
127+
this._handle.setLocalAddress(ipv4, ipv6);
128+
}
117129
}
118130

119131
let defaultResolver = new Resolver();
Collapse file

‎src/cares_wrap.cc‎

Copy file name to clipboardExpand all lines: src/cares_wrap.cc
+66Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "req_wrap-inl.h"
3030
#include "util-inl.h"
3131
#include "uv.h"
32+
#include "node_errors.h"
3233

3334
#include <cerrno>
3435
#include <cstring>
@@ -2227,6 +2228,70 @@ void SetServers(const FunctionCallbackInfo<Value>& args) {
22272228
args.GetReturnValue().Set(err);
22282229
}
22292230

2231+
void SetLocalAddress(const FunctionCallbackInfo<Value>& args) {
2232+
Environment* env = Environment::GetCurrent(args);
2233+
ChannelWrap* channel;
2234+
ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder());
2235+
2236+
CHECK_EQ(args.Length(), 2);
2237+
CHECK(args[0]->IsString());
2238+
2239+
Isolate* isolate = args.GetIsolate();
2240+
node::Utf8Value ip0(isolate, args[0]);
2241+
2242+
unsigned char addr0[sizeof(struct in6_addr)];
2243+
unsigned char addr1[sizeof(struct in6_addr)];
2244+
int type0 = 0;
2245+
2246+
// This function accepts 2 arguments. The first may be either an IPv4
2247+
// address or an IPv6 address. If present, the second argument must be the
2248+
// other type of address. Otherwise, the unspecified type of IP is set
2249+
// to 0 (any).
2250+
2251+
if (uv_inet_pton(AF_INET, *ip0, &addr0) == 0) {
2252+
ares_set_local_ip4(channel->cares_channel(), ReadUint32BE(addr0));
2253+
type0 = 4;
2254+
} else if (uv_inet_pton(AF_INET6, *ip0, &addr0) == 0) {
2255+
ares_set_local_ip6(channel->cares_channel(), addr0);
2256+
type0 = 6;
2257+
} else {
2258+
THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP address.");
2259+
return;
2260+
}
2261+
2262+
if (!args[1]->IsUndefined()) {
2263+
CHECK(args[1]->IsString());
2264+
node::Utf8Value ip1(isolate, args[1]);
2265+
2266+
if (uv_inet_pton(AF_INET, *ip1, &addr1) == 0) {
2267+
if (type0 == 4) {
2268+
THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv4 addresses.");
2269+
return;
2270+
} else {
2271+
ares_set_local_ip4(channel->cares_channel(), ReadUint32BE(addr1));
2272+
}
2273+
} else if (uv_inet_pton(AF_INET6, *ip1, &addr1) == 0) {
2274+
if (type0 == 6) {
2275+
THROW_ERR_INVALID_ARG_VALUE(env, "Cannot specify two IPv6 addresses.");
2276+
return;
2277+
} else {
2278+
ares_set_local_ip6(channel->cares_channel(), addr1);
2279+
}
2280+
} else {
2281+
THROW_ERR_INVALID_ARG_VALUE(env, "Invalid IP address.");
2282+
return;
2283+
}
2284+
} else {
2285+
// No second arg specifed
2286+
if (type0 == 4) {
2287+
memset(&addr1, 0, sizeof(addr1));
2288+
ares_set_local_ip6(channel->cares_channel(), addr1);
2289+
} else {
2290+
ares_set_local_ip4(channel->cares_channel(), 0);
2291+
}
2292+
}
2293+
}
2294+
22302295
void Cancel(const FunctionCallbackInfo<Value>& args) {
22312296
ChannelWrap* channel;
22322297
ASSIGN_OR_RETURN_UNWRAP(&channel, args.Holder());
@@ -2329,6 +2394,7 @@ void Initialize(Local<Object> target,
23292394

23302395
env->SetProtoMethodNoSideEffect(channel_wrap, "getServers", GetServers);
23312396
env->SetProtoMethod(channel_wrap, "setServers", SetServers);
2397+
env->SetProtoMethod(channel_wrap, "setLocalAddress", SetLocalAddress);
23322398
env->SetProtoMethod(channel_wrap, "cancel", Cancel);
23332399

23342400
Local<String> channelWrapString =
Collapse file
+37Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'use strict';
2+
require('../common');
3+
const assert = require('assert');
4+
5+
const dns = require('dns');
6+
const resolver = new dns.Resolver();
7+
const promiseResolver = new dns.promises.Resolver();
8+
9+
// Verifies that setLocalAddress succeeds with IPv4 and IPv6 addresses
10+
{
11+
resolver.setLocalAddress('127.0.0.1');
12+
resolver.setLocalAddress('::1');
13+
resolver.setLocalAddress('127.0.0.1', '::1');
14+
promiseResolver.setLocalAddress('127.0.0.1', '::1');
15+
}
16+
17+
// Verify that setLocalAddress throws if called with an invalid address
18+
{
19+
assert.throws(() => {
20+
resolver.setLocalAddress('127.0.0.1', '127.0.0.1');
21+
}, Error);
22+
assert.throws(() => {
23+
resolver.setLocalAddress('::1', '::1');
24+
}, Error);
25+
assert.throws(() => {
26+
resolver.setLocalAddress('bad');
27+
}, Error);
28+
assert.throws(() => {
29+
resolver.setLocalAddress(123);
30+
}, Error);
31+
assert.throws(() => {
32+
resolver.setLocalAddress();
33+
}, Error);
34+
assert.throws(() => {
35+
promiseResolver.setLocalAddress();
36+
}, Error);
37+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.