Skip to content

Commit 54facc9

Browse files
committed
permission,dns: add permission for dns
1 parent ce531af commit 54facc9

17 files changed

+289
-6
lines changed

doc/api/cli.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,48 @@ Error: Access to this API has been restricted
357357
}
358358
```
359359

360+
### `--allow-net-dns`
361+
362+
<!-- YAML
363+
added: REPLACEME
364+
-->
365+
366+
> Stability: 1.1 - Active development
367+
368+
When using the [Permission Model][], the process will not be able to make dns query
369+
by default.
370+
Attempts to do so will throw an `ERR_ACCESS_DENIED` unless the
371+
user explicitly passes the `--allow-net-dns` flag when starting Node.js.
372+
373+
Example:
374+
375+
```js
376+
const dns = require('node:dns');
377+
dns.lookup("localhost", () => {});
378+
```
379+
380+
```console
381+
$ node --experimental-permission --allow-fs-read=\* index.js
382+
node:dns:235
383+
const err = cares.getaddrinfo(
384+
^
385+
386+
Error: Access to this API has been restricted
387+
at Object.lookup (node:dns:235:21)
388+
at Object.<anonymous> (/home/index.js:2:5)
389+
at Module._compile (node:internal/modules/cjs/loader:1460:14)
390+
at Module._extensions..js (node:internal/modules/cjs/loader:1544:10)
391+
at Module.load (node:internal/modules/cjs/loader:1275:32)
392+
at Module._load (node:internal/modules/cjs/loader:1091:12)
393+
at wrapModuleLoad (node:internal/modules/cjs/loader:212:19)
394+
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:158:5)
395+
at node:internal/main/run_main_module:30:49 {
396+
code: 'ERR_ACCESS_DENIED',
397+
permission: 'NetDNS',
398+
resource: 'lookup'
399+
}
400+
```
401+
360402
### `--build-snapshot`
361403

362404
<!-- YAML
@@ -1012,6 +1054,7 @@ following permissions are restricted:
10121054
* Child Process - manageable through [`--allow-child-process`][] flag
10131055
* Worker Threads - manageable through [`--allow-worker`][] flag
10141056
* WASI - manageable through [`--allow-wasi`][] flag
1057+
* DNS - manageable through [`--allow-net-dns`][] flag
10151058

10161059
### `--experimental-require-module`
10171060

@@ -2804,6 +2847,7 @@ one is included in the list below.
28042847
* `--allow-child-process`
28052848
* `--allow-fs-read`
28062849
* `--allow-fs-write`
2850+
* `--allow-net-dns`
28072851
* `--allow-wasi`
28082852
* `--allow-worker`
28092853
* `--conditions`, `-C`
@@ -3356,6 +3400,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12
33563400
[`--allow-child-process`]: #--allow-child-process
33573401
[`--allow-fs-read`]: #--allow-fs-read
33583402
[`--allow-fs-write`]: #--allow-fs-write
3403+
[`--allow-net-dns`]: #--allow-net-dns
33593404
[`--allow-wasi`]: #--allow-wasi
33603405
[`--allow-worker`]: #--allow-worker
33613406
[`--build-snapshot`]: #--build-snapshot

doc/api/permissions.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,8 @@ Allowing access to spawning a process and creating worker threads can be done
507507
using the [`--allow-child-process`][] and [`--allow-worker`][] respectively.
508508

509509
To allow native addons when using permission model, use the [`--allow-addons`][]
510-
flag. For WASI, use the [`--allow-wasi`][] flag.
510+
flag. For WASI, use the [`--allow-wasi`][] flag. For DNS, use the [`--allow-net-dns`][]
511+
flag.
511512

512513
#### Runtime API
513514

@@ -575,6 +576,7 @@ There are constraints you need to know before using this system:
575576
* Inspector protocol
576577
* File system access
577578
* WASI
579+
* DNS
578580
* The Permission Model is initialized after the Node.js environment is set up.
579581
However, certain flags such as `--env-file` or `--openssl-config` are designed
580582
to read files before environment initialization. As a result, such flags are
@@ -598,6 +600,7 @@ There are constraints you need to know before using this system:
598600
[`--allow-child-process`]: cli.md#--allow-child-process
599601
[`--allow-fs-read`]: cli.md#--allow-fs-read
600602
[`--allow-fs-write`]: cli.md#--allow-fs-write
603+
[`--allow-net-dns`]: cli.md#--allow-net-dns
601604
[`--allow-wasi`]: cli.md#--allow-wasi
602605
[`--allow-worker`]: cli.md#--allow-worker
603606
[`--experimental-permission`]: cli.md#--experimental-permission

doc/node.1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ Allow execution of WASI when using the permission model.
9494
.It Fl -allow-worker
9595
Allow creating worker threads when using the permission model.
9696
.
97+
.It Fl -allow-net-dns
98+
Allow execution of DNS when using the permission model.
99+
.
97100
.It Fl -completion-bash
98101
Print source-able bash completion script for Node.js.
99102
.

lib/internal/process/pre_execution.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ function initializePermission() {
530530
const warnFlags = [
531531
'--allow-addons',
532532
'--allow-child-process',
533+
'--allow-net-dns',
533534
'--allow-wasi',
534535
'--allow-worker',
535536
];
@@ -574,6 +575,7 @@ function initializePermission() {
574575
'--allow-child-process',
575576
'--allow-wasi',
576577
'--allow-worker',
578+
'--allow-net-dns',
577579
];
578580
ArrayPrototypeForEach(availablePermissionFlags, (flag) => {
579581
const value = getOptionValue(flag);

node.gyp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@
155155
'src/permission/permission.cc',
156156
'src/permission/wasi_permission.cc',
157157
'src/permission/worker_permission.cc',
158+
'src/permission/net_dns_permission.cc',
158159
'src/pipe_wrap.cc',
159160
'src/process_wrap.cc',
160161
'src/signal_wrap.cc',
@@ -280,6 +281,7 @@
280281
'src/permission/permission.h',
281282
'src/permission/wasi_permission.h',
282283
'src/permission/worker_permission.h',
284+
'src/permission/net_dns_permission.h',
283285
'src/pipe_wrap.h',
284286
'src/req_wrap.h',
285287
'src/req_wrap-inl.h',

src/cares_wrap.cc

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "node.h"
3030
#include "node_errors.h"
3131
#include "node_external_reference.h"
32+
#include "permission/permission.h"
3233
#include "req_wrap-inl.h"
3334
#include "util-inl.h"
3435
#include "uv.h"
@@ -1417,6 +1418,8 @@ static void Query(const FunctionCallbackInfo<Value>& args) {
14171418
node::Utf8Value utf8name(env->isolate(), string);
14181419
auto plain_name = utf8name.ToStringView();
14191420
std::string name = ada::idna::to_ascii(plain_name);
1421+
THROW_IF_INSUFFICIENT_PERMISSIONS(
1422+
env, permission::PermissionScope::kNetDNS, name);
14201423
channel->ModifyActivityQueryCount(1);
14211424
int err = wrap->Send(name.c_str());
14221425
if (err) {
@@ -1429,7 +1432,6 @@ static void Query(const FunctionCallbackInfo<Value>& args) {
14291432
args.GetReturnValue().Set(err);
14301433
}
14311434

1432-
14331435
void AfterGetAddrInfo(uv_getaddrinfo_t* req, int status, struct addrinfo* res) {
14341436
auto cleanup = OnScopeLeave([&]() { uv_freeaddrinfo(res); });
14351437
BaseObjectPtr<GetAddrInfoReqWrap> req_wrap{
@@ -1568,15 +1570,15 @@ void CanonicalizeIP(const FunctionCallbackInfo<Value>& args) {
15681570

15691571
void GetAddrInfo(const FunctionCallbackInfo<Value>& args) {
15701572
Environment* env = Environment::GetCurrent(args);
1571-
15721573
CHECK(args[0]->IsObject());
15731574
CHECK(args[1]->IsString());
15741575
CHECK(args[2]->IsInt32());
15751576
CHECK(args[4]->IsUint32());
15761577
Local<Object> req_wrap_obj = args[0].As<Object>();
15771578
node::Utf8Value hostname(env->isolate(), args[1]);
15781579
std::string ascii_hostname = ada::idna::to_ascii(hostname.ToStringView());
1579-
1580+
THROW_IF_INSUFFICIENT_PERMISSIONS(
1581+
env, permission::PermissionScope::kNetDNS, ascii_hostname);
15801582
int32_t flags = 0;
15811583
if (args[3]->IsInt32()) {
15821584
flags = args[3].As<Int32>()->Value();
@@ -1639,7 +1641,10 @@ void GetNameInfo(const FunctionCallbackInfo<Value>& args) {
16391641
node::Utf8Value ip(env->isolate(), args[1]);
16401642
const unsigned port = args[2]->Uint32Value(env->context()).FromJust();
16411643
struct sockaddr_storage addr;
1642-
1644+
THROW_IF_INSUFFICIENT_PERMISSIONS(
1645+
env,
1646+
permission::PermissionScope::kNetDNS,
1647+
(*ip + std::string(":") + std::to_string(port)));
16431648
CHECK(uv_ip4_addr(*ip, port, reinterpret_cast<sockaddr_in*>(&addr)) == 0 ||
16441649
uv_ip6_addr(*ip, port, reinterpret_cast<sockaddr_in6*>(&addr)) == 0);
16451650

src/env.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -936,6 +936,9 @@ Environment::Environment(IsolateData* isolate_data,
936936
options_->allow_fs_write,
937937
permission::PermissionScope::kFileSystemWrite);
938938
}
939+
if (!options_->allow_net_dns) {
940+
permission()->Apply(this, {"*"}, permission::PermissionScope::kNetDNS);
941+
}
939942
}
940943
}
941944

src/node_options.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,10 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
464464
"allow worker threads when any permissions are set",
465465
&EnvironmentOptions::allow_worker_threads,
466466
kAllowedInEnvvar);
467+
AddOption("--allow-net-dns",
468+
"allow dns when any permissions are set",
469+
&EnvironmentOptions::allow_net_dns,
470+
kAllowedInEnvvar);
467471
AddOption("--experimental-repl-await",
468472
"experimental await keyword support in REPL",
469473
&EnvironmentOptions::experimental_repl_await,

src/node_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ class EnvironmentOptions : public Options {
132132
bool allow_child_process = false;
133133
bool allow_wasi = false;
134134
bool allow_worker_threads = false;
135+
bool allow_net_dns = false;
135136
bool experimental_repl_await = true;
136137
bool experimental_vm_modules = false;
137138
bool expose_internals = false;

src/permission/net_dns_permission.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include "net_dns_permission.h"
2+
3+
#include <string>
4+
#include <vector>
5+
6+
namespace node {
7+
8+
namespace permission {
9+
10+
void NetDNSPermission::Apply(Environment* env,
11+
const std::vector<std::string>& allow,
12+
PermissionScope scope) {
13+
deny_all_ = true;
14+
}
15+
16+
bool NetDNSPermission::is_granted(Environment* env,
17+
PermissionScope perm,
18+
const std::string_view& param) const {
19+
return deny_all_ == false;
20+
}
21+
22+
} // namespace permission
23+
} // namespace node

0 commit comments

Comments
 (0)