Skip to content

Commit a4169ce

Browse files
jasnellMylesBorins
authored andcommittedApr 4, 2021
net: make net.BlockList cloneable
Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: #37917 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent ae70aa3 commit a4169ce

File tree

9 files changed

+247
-55
lines changed

9 files changed

+247
-55
lines changed
 

‎doc/api/worker_threads.md

+4
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,9 @@ are part of the channel.
527527
<!-- YAML
528528
added: v10.5.0
529529
changes:
530+
- version: REPLACEME
531+
pr-url: https://github.com/nodejs/node/pull/37917
532+
description: Add 'BlockList' to the list of cloneable types.
530533
- version: v15.9.0
531534
pr-url: https://github.com/nodejs/node/pull/37155
532535
description: Add 'Histogram' types to the list of cloneable types.
@@ -569,6 +572,7 @@ In particular, the significant differences to `JSON` are:
569572
* {Histogram}s,
570573
* {KeyObject}s,
571574
* {MessagePort}s,
575+
* {net.BlockList}s,
572576
* {X509Certificate}s.
573577

574578
```js

‎lib/internal/blocklist.js

+41-10
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const {
44
Boolean,
5+
ObjectSetPrototypeOf,
56
Symbol
67
} = primordials;
78

@@ -14,26 +15,28 @@ const {
1415
const {
1516
customInspectSymbol: kInspect,
1617
} = require('internal/util');
18+
19+
const {
20+
JSTransferable,
21+
kClone,
22+
kDeserialize,
23+
} = require('internal/worker/js_transferable');
24+
1725
const { inspect } = require('internal/util/inspect');
1826

1927
const kHandle = Symbol('kHandle');
2028
const { owner_symbol } = internalBinding('symbols');
2129

2230
const {
23-
ERR_INVALID_ARG_TYPE,
2431
ERR_INVALID_ARG_VALUE,
2532
} = require('internal/errors').codes;
2633

2734
const { validateInt32, validateString } = require('internal/validators');
2835

29-
class BlockList {
30-
constructor(handle = new BlockListHandle()) {
31-
// The handle argument is an intentionally undocumented
32-
// internal API. User code will not be able to create
33-
// a BlockListHandle object directly.
34-
if (!(handle instanceof BlockListHandle))
35-
throw new ERR_INVALID_ARG_TYPE('handle', 'BlockListHandle', handle);
36-
this[kHandle] = handle;
36+
class BlockList extends JSTransferable {
37+
constructor() {
38+
super();
39+
this[kHandle] = new BlockListHandle();
3740
this[kHandle][owner_symbol] = this;
3841
}
3942

@@ -107,6 +110,34 @@ class BlockList {
107110
get rules() {
108111
return this[kHandle].getRules();
109112
}
113+
114+
[kClone]() {
115+
const handle = this[kHandle];
116+
return {
117+
data: { handle },
118+
deserializeInfo: 'internal/blocklist:InternalBlockList',
119+
};
120+
}
121+
122+
[kDeserialize]({ handle }) {
123+
this[kHandle] = handle;
124+
this[kHandle][owner_symbol] = this;
125+
}
126+
}
127+
128+
class InternalBlockList extends JSTransferable {
129+
constructor(handle) {
130+
super();
131+
this[kHandle] = handle;
132+
if (handle !== undefined)
133+
handle[owner_symbol] = this;
134+
}
110135
}
111136

112-
module.exports = BlockList;
137+
InternalBlockList.prototype.constructor = BlockList.prototype.constructor;
138+
ObjectSetPrototypeOf(InternalBlockList.prototype, BlockList.prototype);
139+
140+
module.exports = {
141+
BlockList,
142+
InternalBlockList,
143+
};

‎lib/net.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1748,8 +1748,7 @@ module.exports = {
17481748
_normalizeArgs: normalizeArgs,
17491749
_setSimultaneousAccepts,
17501750
get BlockList() {
1751-
if (BlockList === undefined)
1752-
BlockList = require('internal/blocklist');
1751+
BlockList ??= require('internal/blocklist').BlockList;
17531752
return BlockList;
17541753
},
17551754
connect,

‎src/env-inl.h

+7-4
Original file line numberDiff line numberDiff line change
@@ -1035,15 +1035,18 @@ inline void Environment::SetInstanceMethod(v8::Local<v8::FunctionTemplate> that,
10351035
inline void Environment::SetConstructorFunction(
10361036
v8::Local<v8::Object> that,
10371037
const char* name,
1038-
v8::Local<v8::FunctionTemplate> tmpl) {
1039-
SetConstructorFunction(that, OneByteString(isolate(), name), tmpl);
1038+
v8::Local<v8::FunctionTemplate> tmpl,
1039+
SetConstructorFunctionFlag flag) {
1040+
SetConstructorFunction(that, OneByteString(isolate(), name), tmpl, flag);
10401041
}
10411042

10421043
inline void Environment::SetConstructorFunction(
10431044
v8::Local<v8::Object> that,
10441045
v8::Local<v8::String> name,
1045-
v8::Local<v8::FunctionTemplate> tmpl) {
1046-
tmpl->SetClassName(name);
1046+
v8::Local<v8::FunctionTemplate> tmpl,
1047+
SetConstructorFunctionFlag flag) {
1048+
if (LIKELY(flag == SetConstructorFunctionFlag::SET_CLASS_NAME))
1049+
tmpl->SetClassName(name);
10471050
that->Set(
10481051
context(),
10491052
name,

‎src/env.h

+12-3
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ constexpr size_t kFsStatsBufferLength =
442442
V(base_object_ctor_template, v8::FunctionTemplate) \
443443
V(binding_data_ctor_template, v8::FunctionTemplate) \
444444
V(blob_constructor_template, v8::FunctionTemplate) \
445-
V(blocklist_instance_template, v8::ObjectTemplate) \
445+
V(blocklist_constructor_template, v8::FunctionTemplate) \
446446
V(compiled_fn_entry_template, v8::ObjectTemplate) \
447447
V(dir_instance_template, v8::ObjectTemplate) \
448448
V(fd_constructor_template, v8::ObjectTemplate) \
@@ -1231,13 +1231,22 @@ class Environment : public MemoryRetainer {
12311231
const char* name,
12321232
v8::FunctionCallback callback);
12331233

1234+
enum class SetConstructorFunctionFlag {
1235+
NONE,
1236+
SET_CLASS_NAME,
1237+
};
1238+
12341239
inline void SetConstructorFunction(v8::Local<v8::Object> that,
12351240
const char* name,
1236-
v8::Local<v8::FunctionTemplate> tmpl);
1241+
v8::Local<v8::FunctionTemplate> tmpl,
1242+
SetConstructorFunctionFlag flag =
1243+
SetConstructorFunctionFlag::SET_CLASS_NAME);
12371244

12381245
inline void SetConstructorFunction(v8::Local<v8::Object> that,
12391246
v8::Local<v8::String> name,
1240-
v8::Local<v8::FunctionTemplate> tmpl);
1247+
v8::Local<v8::FunctionTemplate> tmpl,
1248+
SetConstructorFunctionFlag flag =
1249+
SetConstructorFunctionFlag::SET_CLASS_NAME);
12411250

12421251
void AtExit(void (*cb)(void* arg), void* arg);
12431252
void RunAtExitCallbacks();

‎src/node_sockaddr.cc

+102-25
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ SocketAddressBlockList::SocketAddressBlockList(
390390

391391
void SocketAddressBlockList::AddSocketAddress(
392392
const SocketAddress& address) {
393+
Mutex::ScopedLock lock(mutex_);
393394
std::unique_ptr<Rule> rule =
394395
std::make_unique<SocketAddressRule>(address);
395396
rules_.emplace_front(std::move(rule));
@@ -398,6 +399,7 @@ void SocketAddressBlockList::AddSocketAddress(
398399

399400
void SocketAddressBlockList::RemoveSocketAddress(
400401
const SocketAddress& address) {
402+
Mutex::ScopedLock lock(mutex_);
401403
auto it = address_rules_.find(address);
402404
if (it != std::end(address_rules_)) {
403405
rules_.erase(it->second);
@@ -408,6 +410,7 @@ void SocketAddressBlockList::RemoveSocketAddress(
408410
void SocketAddressBlockList::AddSocketAddressRange(
409411
const SocketAddress& start,
410412
const SocketAddress& end) {
413+
Mutex::ScopedLock lock(mutex_);
411414
std::unique_ptr<Rule> rule =
412415
std::make_unique<SocketAddressRangeRule>(start, end);
413416
rules_.emplace_front(std::move(rule));
@@ -416,12 +419,14 @@ void SocketAddressBlockList::AddSocketAddressRange(
416419
void SocketAddressBlockList::AddSocketAddressMask(
417420
const SocketAddress& network,
418421
int prefix) {
422+
Mutex::ScopedLock lock(mutex_);
419423
std::unique_ptr<Rule> rule =
420424
std::make_unique<SocketAddressMaskRule>(network, prefix);
421425
rules_.emplace_front(std::move(rule));
422426
}
423427

424428
bool SocketAddressBlockList::Apply(const SocketAddress& address) {
429+
Mutex::ScopedLock lock(mutex_);
425430
for (const auto& rule : rules_) {
426431
if (rule->Apply(address))
427432
return true;
@@ -488,14 +493,25 @@ std::string SocketAddressBlockList::SocketAddressMaskRule::ToString() {
488493
}
489494

490495
MaybeLocal<Array> SocketAddressBlockList::ListRules(Environment* env) {
496+
Mutex::ScopedLock lock(mutex_);
491497
std::vector<Local<Value>> rules;
498+
if (!ListRules(env, &rules))
499+
return MaybeLocal<Array>();
500+
return Array::New(env->isolate(), rules.data(), rules.size());
501+
}
502+
503+
bool SocketAddressBlockList::ListRules(
504+
Environment* env,
505+
std::vector<v8::Local<v8::Value>>* rules) {
506+
if (parent_ && !parent_->ListRules(env, rules))
507+
return false;
492508
for (const auto& rule : rules_) {
493509
Local<Value> str;
494510
if (!rule->ToV8String(env).ToLocal(&str))
495-
return MaybeLocal<Array>();
496-
rules.push_back(str);
511+
return false;
512+
rules->push_back(str);
497513
}
498-
return Array::New(env->isolate(), rules.data(), rules.size());
514+
return true;
499515
}
500516

501517
void SocketAddressBlockList::MemoryInfo(node::MemoryTracker* tracker) const {
@@ -519,20 +535,42 @@ void SocketAddressBlockList::SocketAddressMaskRule::MemoryInfo(
519535
}
520536

521537
SocketAddressBlockListWrap::SocketAddressBlockListWrap(
522-
Environment* env, Local<Object> wrap)
523-
: BaseObject(env, wrap) {
538+
Environment* env,
539+
Local<Object> wrap,
540+
std::shared_ptr<SocketAddressBlockList> blocklist)
541+
: BaseObject(env, wrap),
542+
blocklist_(std::move(blocklist)) {
524543
MakeWeak();
525544
}
526545

527546
BaseObjectPtr<SocketAddressBlockListWrap> SocketAddressBlockListWrap::New(
528547
Environment* env) {
529548
Local<Object> obj;
530-
if (!env->blocklist_instance_template()
549+
if (!env->blocklist_constructor_template()
550+
->InstanceTemplate()
551+
->NewInstance(env->context()).ToLocal(&obj)) {
552+
return BaseObjectPtr<SocketAddressBlockListWrap>();
553+
}
554+
BaseObjectPtr<SocketAddressBlockListWrap> wrap =
555+
MakeBaseObject<SocketAddressBlockListWrap>(env, obj);
556+
CHECK(wrap);
557+
return wrap;
558+
}
559+
560+
BaseObjectPtr<SocketAddressBlockListWrap> SocketAddressBlockListWrap::New(
561+
Environment* env,
562+
std::shared_ptr<SocketAddressBlockList> blocklist) {
563+
Local<Object> obj;
564+
if (!env->blocklist_constructor_template()
565+
->InstanceTemplate()
531566
->NewInstance(env->context()).ToLocal(&obj)) {
532-
return {};
567+
return BaseObjectPtr<SocketAddressBlockListWrap>();
533568
}
534569
BaseObjectPtr<SocketAddressBlockListWrap> wrap =
535-
MakeDetachedBaseObject<SocketAddressBlockListWrap>(env, obj);
570+
MakeBaseObject<SocketAddressBlockListWrap>(
571+
env,
572+
obj,
573+
std::move(blocklist));
536574
CHECK(wrap);
537575
return wrap;
538576
}
@@ -562,7 +600,7 @@ void SocketAddressBlockListWrap::AddAddress(
562600
if (!SocketAddress::ToSockAddr(family, *value, 0, &address))
563601
return;
564602

565-
wrap->AddSocketAddress(
603+
wrap->blocklist_->AddSocketAddress(
566604
SocketAddress(reinterpret_cast<const sockaddr*>(&address)));
567605

568606
args.GetReturnValue().Set(true);
@@ -597,7 +635,7 @@ void SocketAddressBlockListWrap::AddRange(
597635
if (start_addr > end_addr)
598636
return args.GetReturnValue().Set(false);
599637

600-
wrap->AddSocketAddressRange(start_addr, end_addr);
638+
wrap->blocklist_->AddSocketAddressRange(start_addr, end_addr);
601639

602640
args.GetReturnValue().Set(true);
603641
}
@@ -628,7 +666,7 @@ void SocketAddressBlockListWrap::AddSubnet(
628666
CHECK_IMPLIES(family == AF_INET6, prefix <= 128);
629667
CHECK_GE(prefix, 0);
630668

631-
wrap->AddSocketAddressMask(
669+
wrap->blocklist_->AddSocketAddressMask(
632670
SocketAddress(reinterpret_cast<const sockaddr*>(&address)),
633671
prefix);
634672

@@ -654,7 +692,8 @@ void SocketAddressBlockListWrap::Check(
654692
return;
655693

656694
args.GetReturnValue().Set(
657-
wrap->Apply(SocketAddress(reinterpret_cast<const sockaddr*>(&address))));
695+
wrap->blocklist_->Apply(
696+
SocketAddress(reinterpret_cast<const sockaddr*>(&address))));
658697
}
659698

660699
void SocketAddressBlockListWrap::GetRules(
@@ -663,34 +702,72 @@ void SocketAddressBlockListWrap::GetRules(
663702
SocketAddressBlockListWrap* wrap;
664703
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
665704
Local<Array> rules;
666-
if (wrap->ListRules(env).ToLocal(&rules))
705+
if (wrap->blocklist_->ListRules(env).ToLocal(&rules))
667706
args.GetReturnValue().Set(rules);
668707
}
669708

709+
void SocketAddressBlockListWrap::MemoryInfo(MemoryTracker* tracker) const {
710+
blocklist_->MemoryInfo(tracker);
711+
}
712+
713+
std::unique_ptr<worker::TransferData>
714+
SocketAddressBlockListWrap::CloneForMessaging() const {
715+
return std::make_unique<TransferData>(this);
716+
}
717+
718+
bool SocketAddressBlockListWrap::HasInstance(
719+
Environment* env,
720+
Local<Value> value) {
721+
return GetConstructorTemplate(env)->HasInstance(value);
722+
}
723+
724+
Local<FunctionTemplate> SocketAddressBlockListWrap::GetConstructorTemplate(
725+
Environment* env) {
726+
Local<FunctionTemplate> tmpl = env->blocklist_constructor_template();
727+
if (tmpl.IsEmpty()) {
728+
tmpl = env->NewFunctionTemplate(SocketAddressBlockListWrap::New);
729+
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "BlockList"));
730+
tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
731+
tmpl->InstanceTemplate()->SetInternalFieldCount(kInternalFieldCount);
732+
env->SetProtoMethod(tmpl, "addAddress", AddAddress);
733+
env->SetProtoMethod(tmpl, "addRange", AddRange);
734+
env->SetProtoMethod(tmpl, "addSubnet", AddSubnet);
735+
env->SetProtoMethod(tmpl, "check", Check);
736+
env->SetProtoMethod(tmpl, "getRules", GetRules);
737+
env->set_blocklist_constructor_template(tmpl);
738+
}
739+
return tmpl;
740+
}
741+
670742
void SocketAddressBlockListWrap::Initialize(
671743
Local<Object> target,
672744
Local<Value> unused,
673745
Local<Context> context,
674746
void* priv) {
675747
Environment* env = Environment::GetCurrent(context);
676748

677-
Local<FunctionTemplate> t =
678-
env->NewFunctionTemplate(SocketAddressBlockListWrap::New);
679-
t->InstanceTemplate()->SetInternalFieldCount(BaseObject::kInternalFieldCount);
680-
681-
env->SetProtoMethod(t, "addAddress", SocketAddressBlockListWrap::AddAddress);
682-
env->SetProtoMethod(t, "addRange", SocketAddressBlockListWrap::AddRange);
683-
env->SetProtoMethod(t, "addSubnet", SocketAddressBlockListWrap::AddSubnet);
684-
env->SetProtoMethod(t, "check", SocketAddressBlockListWrap::Check);
685-
env->SetProtoMethod(t, "getRules", SocketAddressBlockListWrap::GetRules);
686-
687-
env->set_blocklist_instance_template(t->InstanceTemplate());
688-
env->SetConstructorFunction(target, "BlockList", t);
749+
env->SetConstructorFunction(
750+
target,
751+
"BlockList",
752+
GetConstructorTemplate(env),
753+
Environment::SetConstructorFunctionFlag::NONE);
689754

690755
NODE_DEFINE_CONSTANT(target, AF_INET);
691756
NODE_DEFINE_CONSTANT(target, AF_INET6);
692757
}
693758

759+
BaseObjectPtr<BaseObject> SocketAddressBlockListWrap::TransferData::Deserialize(
760+
Environment* env,
761+
Local<Context> context,
762+
std::unique_ptr<worker::TransferData> self) {
763+
return New(env, std::move(blocklist_));
764+
}
765+
766+
void SocketAddressBlockListWrap::TransferData::MemoryInfo(
767+
MemoryTracker* tracker) const {
768+
blocklist_->MemoryInfo(tracker);
769+
}
770+
694771
} // namespace node
695772

696773
NODE_MODULE_CONTEXT_AWARE_INTERNAL(

‎src/node_sockaddr.h

+49-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "memory_tracker.h"
88
#include "base_object.h"
99
#include "node.h"
10+
#include "node_worker.h"
1011
#include "uv.h"
1112
#include "v8.h"
1213

@@ -267,21 +268,32 @@ class SocketAddressBlockList : public MemoryRetainer {
267268
SET_SELF_SIZE(SocketAddressBlockList)
268269

269270
private:
271+
bool ListRules(
272+
Environment* env,
273+
std::vector<v8::Local<v8::Value>>* vec);
274+
270275
std::shared_ptr<SocketAddressBlockList> parent_;
271276
std::list<std::unique_ptr<Rule>> rules_;
272277
SocketAddress::Map<std::list<std::unique_ptr<Rule>>::iterator> address_rules_;
278+
279+
Mutex mutex_;
273280
};
274281

275-
class SocketAddressBlockListWrap :
276-
public BaseObject,
277-
public SocketAddressBlockList {
282+
class SocketAddressBlockListWrap : public BaseObject {
278283
public:
284+
static bool HasInstance(Environment* env, v8::Local<v8::Value> value);
285+
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
286+
Environment* env);
279287
static void Initialize(v8::Local<v8::Object> target,
280288
v8::Local<v8::Value> unused,
281289
v8::Local<v8::Context> context,
282290
void* priv);
283291

284292
static BaseObjectPtr<SocketAddressBlockListWrap> New(Environment* env);
293+
static BaseObjectPtr<SocketAddressBlockListWrap> New(
294+
Environment* env,
295+
std::shared_ptr<SocketAddressBlockList> blocklist);
296+
285297
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
286298
static void AddAddress(const v8::FunctionCallbackInfo<v8::Value>& args);
287299
static void AddRange(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -291,13 +303,43 @@ class SocketAddressBlockListWrap :
291303

292304
SocketAddressBlockListWrap(
293305
Environment* env,
294-
v8::Local<v8::Object> wrap);
306+
v8::Local<v8::Object> wrap,
307+
std::shared_ptr<SocketAddressBlockList> blocklist =
308+
std::make_shared<SocketAddressBlockList>());
295309

296-
void MemoryInfo(node::MemoryTracker* tracker) const override {
297-
SocketAddressBlockList::MemoryInfo(tracker);
298-
}
310+
void MemoryInfo(node::MemoryTracker* tracker) const override;
299311
SET_MEMORY_INFO_NAME(SocketAddressBlockListWrap)
300312
SET_SELF_SIZE(SocketAddressBlockListWrap)
313+
314+
TransferMode GetTransferMode() const override {
315+
return TransferMode::kCloneable;
316+
}
317+
std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
318+
319+
class TransferData : public worker::TransferData {
320+
public:
321+
inline explicit TransferData(const SocketAddressBlockListWrap* wrap)
322+
: blocklist_(wrap->blocklist_) {}
323+
324+
inline explicit TransferData(
325+
std::shared_ptr<SocketAddressBlockList> blocklist)
326+
: blocklist_(std::move(blocklist)) {}
327+
328+
BaseObjectPtr<BaseObject> Deserialize(
329+
Environment* env,
330+
v8::Local<v8::Context> context,
331+
std::unique_ptr<worker::TransferData> self) override;
332+
333+
void MemoryInfo(MemoryTracker* tracker) const override;
334+
SET_MEMORY_INFO_NAME(SocketAddressBlockListWrap::TransferData)
335+
SET_SELF_SIZE(TransferData)
336+
337+
private:
338+
std::shared_ptr<SocketAddressBlockList> blocklist_;
339+
};
340+
341+
private:
342+
std::shared_ptr<SocketAddressBlockList> blocklist_;
301343
};
302344

303345
} // namespace node

‎test/parallel/test-blocklist-clone.js

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
5+
const {
6+
BlockList,
7+
} = require('net');
8+
9+
const {
10+
ok,
11+
notStrictEqual,
12+
} = require('assert');
13+
14+
const blocklist = new BlockList();
15+
blocklist.addAddress('123.123.123.123');
16+
17+
const mc = new MessageChannel();
18+
19+
mc.port1.onmessage = common.mustCall(({ data }) => {
20+
notStrictEqual(data, blocklist);
21+
ok(data.check('123.123.123.123'));
22+
ok(!data.check('123.123.123.124'));
23+
24+
data.addAddress('123.123.123.124');
25+
ok(blocklist.check('123.123.123.124'));
26+
ok(data.check('123.123.123.124'));
27+
28+
mc.port1.close();
29+
});
30+
31+
mc.port2.postMessage(blocklist);

‎test/parallel/test-blocklist.js

-4
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,6 @@ const util = require('util');
137137
assert(!blockList.check('8592:757c:efaf:2fff:ffff:ffff:ffff:ffff', 'ipv6'));
138138
}
139139

140-
{
141-
assert.throws(() => new BlockList('NOT BLOCK LIST HANDLE'), /ERR_INVALID_ARG_TYPE/);
142-
}
143-
144140
{
145141
const blockList = new BlockList();
146142
assert.throws(() => blockList.addRange('1.1.1.2', '1.1.1.1'), /ERR_INVALID_ARG_VALUE/);

0 commit comments

Comments
 (0)
Please sign in to comment.