Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v15.14.0 proposal #38084

Merged
merged 41 commits into from
Apr 6, 2021
Merged
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
913ec56
deps: cjs-module-lexer: cherry-pick 22093e765f
peZhmanParsaee Mar 24, 2021
5e15ae0
test: add DataView test case for v8 serdes
Trott Mar 28, 2021
570fbce
url: forbid pipe in URL host
RaisinTen Mar 23, 2021
13c3924
doc: add Windows-specific info to subprocess.kill()
joaolucasl Aug 21, 2020
bbdcdad
deps: upgrade openssl sources to 1.1.1k+quic
hassaanp Mar 25, 2021
f0e7714
deps: update archs files for OpenSSL-1.1.1k
hassaanp Mar 25, 2021
f3fabb5
doc: add missing cleanup step in OpenSSL upgrade
tniessen Mar 26, 2021
a57dc06
doc: improve Buffer's encoding documentation
targos Mar 27, 2021
d86aca9
http: optimize debug function correctly
targos Mar 29, 2021
a94cc27
path: refactor to use more primordials
marsonya Mar 24, 2021
4ef102d
deps: update to cjs-module-lexer@1.1.1
guybedford Mar 30, 2021
51e7a33
tools,doc: add "legacy" badge in the TOC
aduh95 Mar 27, 2021
062541a
http2: add specific error code for custom frames
addaleax Mar 26, 2021
8792c7c
doc: add missing events.on metadata
addaleax Mar 29, 2021
669b81c
net,tls: add abort signal support to connect
Linkgoron Mar 12, 2021
a1123f0
readline: add AbortSignal support to interface
Linkgoron Mar 26, 2021
6cc1e15
readline: fix pre-aborted signal question handling
Linkgoron Mar 26, 2021
21e399b
lib: change wording in lib/internal/child_process comment
marsonya Mar 25, 2021
8525231
lib: change wording in lib/domain.js comment
marsonya Mar 26, 2021
ae70aa3
doc: add distinctive color for code elements inside links
aduh95 Mar 27, 2021
a4169ce
net: make net.BlockList cloneable
jasnell Mar 25, 2021
daa8a7b
net: add SocketAddress class
jasnell Mar 25, 2021
0709cbb
net: allow net.BlockList to use net.SocketAddress objects
jasnell Mar 25, 2021
4d50975
test: improve clarity of ALS-enable-disable.js
PhakornKiong Mar 31, 2021
ce14080
doc: move psmarshall to collaborators emeriti
psmarshall Mar 31, 2021
ad7e344
fs: fix chown abort
RaisinTen Mar 31, 2021
6ad0b6f
src: fix error handling for CryptoJob::ToResult
tniessen Apr 1, 2021
6d28a24
tools: update ESLint to 7.23.0
lpinca Mar 30, 2021
0db1a1e
test: deflake test-fs-read-optional-params
lpinca Mar 30, 2021
960c6be
crypto: add buffering to randomInt
tniessen Sep 8, 2020
b02c352
test: fix test-tls-no-sslv3 for OpenSSL 3
richardlau Apr 1, 2021
b40d35d
doc: document how to unref stdin when using readline.Interface
AnupamaP Apr 1, 2021
0243376
test: use faster variant for rss
PoojaDurgad Jan 7, 2021
3ab9619
module: improve error message for invalid data URL
aduh95 Mar 10, 2021
3175559
test: add extra space in test failure output
Ayase-252 Mar 28, 2021
afc6ab2
doc: fix asyncLocalStorage.run() description
PhakornKiong Apr 1, 2021
ac69b95
crypto: use correct webcrypto RSASSA-PKCS1-v1_5 algorithm name
panva Apr 1, 2021
e61cc0b
src: fix typos in crypto comments
tniessen Apr 1, 2021
b6f4901
fs: add support for async iterators to `fsPromises.writeFile`
Feb 21, 2021
629e72e
src: fix typo in node_mutex
tniessen Mar 31, 2021
1a34e9c
2021-04-06, Version 15.14.0 (Current)
MylesBorins Apr 5, 2021
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
Prev Previous commit
Next Next commit
net: allow net.BlockList to use net.SocketAddress objects
Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: #37917
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
jasnell authored and MylesBorins committed Apr 4, 2021

Verified

This commit was signed with the committer’s verified signature. The key has expired.
MylesBorins Myles Borins
commit 0709cbb7fefd17687251a59d645b1dc84cdc7927
11 changes: 6 additions & 5 deletions doc/api/net.md
Original file line number Diff line number Diff line change
@@ -69,7 +69,7 @@ IP subnets.
added: v15.0.0
-->

* `address` {string} An IPv4 or IPv6 address.
* `address` {string|net.SocketAddress} An IPv4 or IPv6 address.
* `type` {string} Either `'ipv4'` or `'ipv6'`. **Default:** `'ipv4'`.

Adds a rule to block the given IP address.
@@ -79,8 +79,9 @@ Adds a rule to block the given IP address.
added: v15.0.0
-->

* `start` {string} The starting IPv4 or IPv6 address in the range.
* `end` {string} The ending IPv4 or IPv6 address in the range.
* `start` {string|net.SocketAddress} The starting IPv4 or IPv6 address in the
range.
* `end` {string|net.SocketAddress} The ending IPv4 or IPv6 address in the range.
* `type` {string} Either `'ipv4'` or `'ipv6'`. **Default:** `'ipv4'`.

Adds a rule to block a range of IP addresses from `start` (inclusive) to
@@ -91,7 +92,7 @@ Adds a rule to block a range of IP addresses from `start` (inclusive) to
added: v15.0.0
-->

* `net` {string} The network IPv4 or IPv6 address.
* `net` {string|net.SocketAddress} The network IPv4 or IPv6 address.
* `prefix` {number} The number of CIDR prefix bits. For IPv4, this
must be a value between `0` and `32`. For IPv6, this must be between
`0` and `128`.
@@ -104,7 +105,7 @@ Adds a rule to block a range of IP addresses specified as a subnet mask.
added: v15.0.0
-->

* `address` {string} The IP address to check
* `address` {string|net.SocketAddress} The IP address to check
* `type` {string} Either `'ipv4'` or `'ipv6'`. **Default:** `'ipv4'`.
* Returns: {boolean}

91 changes: 57 additions & 34 deletions lib/internal/blocklist.js
Original file line number Diff line number Diff line change
@@ -8,14 +8,17 @@ const {

const {
BlockList: BlockListHandle,
AF_INET,
AF_INET6,
} = internalBinding('block_list');

const {
customInspectSymbol: kInspect,
} = require('internal/util');

const {
SocketAddress,
kHandle: kSocketAddressHandle,
} = require('internal/socketaddress');

const {
JSTransferable,
kClone,
@@ -55,56 +58,76 @@ class BlockList extends JSTransferable {
}

addAddress(address, family = 'ipv4') {
validateString(address, 'address');
validateString(family, 'family');
family = family.toLowerCase();
if (family !== 'ipv4' && family !== 'ipv6')
throw new ERR_INVALID_ARG_VALUE('family', family);
const type = family === 'ipv4' ? AF_INET : AF_INET6;
this[kHandle].addAddress(address, type);
if (!SocketAddress.isSocketAddress(address)) {
validateString(address, 'address');
validateString(family, 'family');
address = new SocketAddress({
address,
family,
});
}
this[kHandle].addAddress(address[kSocketAddressHandle]);
}

addRange(start, end, family = 'ipv4') {
validateString(start, 'start');
validateString(end, 'end');
validateString(family, 'family');
family = family.toLowerCase();
if (family !== 'ipv4' && family !== 'ipv6')
throw new ERR_INVALID_ARG_VALUE('family', family);
const type = family === 'ipv4' ? AF_INET : AF_INET6;
const ret = this[kHandle].addRange(start, end, type);
if (!SocketAddress.isSocketAddress(start)) {
validateString(start, 'start');
validateString(family, 'family');
start = new SocketAddress({
address: start,
family,
});
}
if (!SocketAddress.isSocketAddress(end)) {
validateString(end, 'end');
validateString(family, 'family');
end = new SocketAddress({
address: end,
family,
});
}
const ret = this[kHandle].addRange(
start[kSocketAddressHandle],
end[kSocketAddressHandle]);
if (ret === false)
throw new ERR_INVALID_ARG_VALUE('start', start, 'must come before end');
}

addSubnet(network, prefix, family = 'ipv4') {
validateString(network, 'network');
validateString(family, 'family');
family = family.toLowerCase();
let type;
switch (family) {
if (!SocketAddress.isSocketAddress(network)) {
validateString(network, 'network');
validateString(family, 'family');
network = new SocketAddress({
address: network,
family,
});
}
switch (network.family) {
case 'ipv4':
type = AF_INET;
validateInt32(prefix, 'prefix', 0, 32);
break;
case 'ipv6':
type = AF_INET6;
validateInt32(prefix, 'prefix', 0, 128);
break;
default:
throw new ERR_INVALID_ARG_VALUE('family', family);
}
this[kHandle].addSubnet(network, type, prefix);
this[kHandle].addSubnet(network[kSocketAddressHandle], prefix);
}

check(address, family = 'ipv4') {
validateString(address, 'address');
validateString(family, 'family');
family = family.toLowerCase();
if (family !== 'ipv4' && family !== 'ipv6')
throw new ERR_INVALID_ARG_VALUE('family', family);
const type = family === 'ipv4' ? AF_INET : AF_INET6;
return Boolean(this[kHandle].check(address, type));
if (!SocketAddress.isSocketAddress(address)) {
validateString(address, 'address');
validateString(family, 'family');
try {
address = new SocketAddress({
address,
family,
});
} catch {
// Ignore the error. If it's not a valid address, return false.
return false;
}
}
return Boolean(this[kHandle].check(address[kSocketAddressHandle]));
}

get rules() {
7 changes: 5 additions & 2 deletions lib/internal/socketaddress.js
Original file line number Diff line number Diff line change
@@ -47,14 +47,16 @@ class SocketAddress extends JSTransferable {
constructor(options = {}) {
super();
validateObject(options, 'options');
let { family = 'ipv4' } = options;
const {
family = 'ipv4',
address = (family === 'ipv4' ? '127.0.0.1' : '::'),
port = 0,
flowlabel = 0,
} = options;

let type;
if (typeof family?.toLowerCase === 'function')
family = family.toLowerCase();
switch (family) {
case 'ipv4':
type = AF_INET;
@@ -63,7 +65,7 @@ class SocketAddress extends JSTransferable {
type = AF_INET6;
break;
default:
throw new ERR_INVALID_ARG_VALUE('options.family', family);
throw new ERR_INVALID_ARG_VALUE('options.family', options.family);
}

validateString(address, 'options.address');
@@ -150,4 +152,5 @@ ObjectSetPrototypeOf(InternalSocketAddress.prototype, SocketAddress.prototype);
module.exports = {
SocketAddress,
InternalSocketAddress,
kHandle,
};
140 changes: 53 additions & 87 deletions src/node_sockaddr.cc
Original file line number Diff line number Diff line change
@@ -392,43 +392,44 @@ SocketAddressBlockList::SocketAddressBlockList(
: parent_(parent) {}

void SocketAddressBlockList::AddSocketAddress(
const SocketAddress& address) {
const std::shared_ptr<SocketAddress>& address) {
Mutex::ScopedLock lock(mutex_);
std::unique_ptr<Rule> rule =
std::make_unique<SocketAddressRule>(address);
rules_.emplace_front(std::move(rule));
address_rules_[address] = rules_.begin();
address_rules_[*address.get()] = rules_.begin();
}

void SocketAddressBlockList::RemoveSocketAddress(
const SocketAddress& address) {
const std::shared_ptr<SocketAddress>& address) {
Mutex::ScopedLock lock(mutex_);
auto it = address_rules_.find(address);
auto it = address_rules_.find(*address.get());
if (it != std::end(address_rules_)) {
rules_.erase(it->second);
address_rules_.erase(it);
}
}

void SocketAddressBlockList::AddSocketAddressRange(
const SocketAddress& start,
const SocketAddress& end) {
const std::shared_ptr<SocketAddress>& start,
const std::shared_ptr<SocketAddress>& end) {
Mutex::ScopedLock lock(mutex_);
std::unique_ptr<Rule> rule =
std::make_unique<SocketAddressRangeRule>(start, end);
rules_.emplace_front(std::move(rule));
}

void SocketAddressBlockList::AddSocketAddressMask(
const SocketAddress& network,
const std::shared_ptr<SocketAddress>& network,
int prefix) {
Mutex::ScopedLock lock(mutex_);
std::unique_ptr<Rule> rule =
std::make_unique<SocketAddressMaskRule>(network, prefix);
rules_.emplace_front(std::move(rule));
}

bool SocketAddressBlockList::Apply(const SocketAddress& address) {
bool SocketAddressBlockList::Apply(
const std::shared_ptr<SocketAddress>& address) {
Mutex::ScopedLock lock(mutex_);
for (const auto& rule : rules_) {
if (rule->Apply(address))
@@ -438,59 +439,60 @@ bool SocketAddressBlockList::Apply(const SocketAddress& address) {
}

SocketAddressBlockList::SocketAddressRule::SocketAddressRule(
const SocketAddress& address_)
const std::shared_ptr<SocketAddress>& address_)
: address(address_) {}

SocketAddressBlockList::SocketAddressRangeRule::SocketAddressRangeRule(
const SocketAddress& start_,
const SocketAddress& end_)
const std::shared_ptr<SocketAddress>& start_,
const std::shared_ptr<SocketAddress>& end_)
: start(start_),
end(end_) {}

SocketAddressBlockList::SocketAddressMaskRule::SocketAddressMaskRule(
const SocketAddress& network_,
const std::shared_ptr<SocketAddress>& network_,
int prefix_)
: network(network_),
prefix(prefix_) {}

bool SocketAddressBlockList::SocketAddressRule::Apply(
const SocketAddress& address) {
return this->address.is_match(address);
const std::shared_ptr<SocketAddress>& address) {
return this->address->is_match(*address.get());
}

std::string SocketAddressBlockList::SocketAddressRule::ToString() {
std::string ret = "Address: ";
ret += address.family() == AF_INET ? "IPv4" : "IPv6";
ret += address->family() == AF_INET ? "IPv4" : "IPv6";
ret += " ";
ret += address.address();
ret += address->address();
return ret;
}

bool SocketAddressBlockList::SocketAddressRangeRule::Apply(
const SocketAddress& address) {
return address >= start && address <= end;
const std::shared_ptr<SocketAddress>& address) {
return *address.get() >= *start.get() &&
*address.get() <= *end.get();
}

std::string SocketAddressBlockList::SocketAddressRangeRule::ToString() {
std::string ret = "Range: ";
ret += start.family() == AF_INET ? "IPv4" : "IPv6";
ret += start->family() == AF_INET ? "IPv4" : "IPv6";
ret += " ";
ret += start.address();
ret += start->address();
ret += "-";
ret += end.address();
ret += end->address();
return ret;
}

bool SocketAddressBlockList::SocketAddressMaskRule::Apply(
const SocketAddress& address) {
return address.is_in_network(network, prefix);
const std::shared_ptr<SocketAddress>& address) {
return address->is_in_network(*network.get(), prefix);
}

std::string SocketAddressBlockList::SocketAddressMaskRule::ToString() {
std::string ret = "Subnet: ";
ret += network.family() == AF_INET ? "IPv4" : "IPv6";
ret += network->family() == AF_INET ? "IPv4" : "IPv6";
ret += " ";
ret += network.address();
ret += network->address();
ret += "/" + std::to_string(prefix);
return ret;
}
@@ -591,20 +593,11 @@ void SocketAddressBlockListWrap::AddAddress(
SocketAddressBlockListWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());

CHECK(args[0]->IsString());
CHECK(args[1]->IsInt32());

sockaddr_storage address;
Utf8Value value(args.GetIsolate(), args[0]);
int32_t family;
if (!args[1]->Int32Value(env->context()).To(&family))
return;

if (!SocketAddress::ToSockAddr(family, *value, 0, &address))
return;
CHECK(SocketAddressBase::HasInstance(env, args[0]));
SocketAddressBase* addr;
ASSIGN_OR_RETURN_UNWRAP(&addr, args[0]);

wrap->blocklist_->AddSocketAddress(
SocketAddress(reinterpret_cast<const sockaddr*>(&address)));
wrap->blocklist_->AddSocketAddress(addr->address());

args.GetReturnValue().Set(true);
}
@@ -615,30 +608,21 @@ void SocketAddressBlockListWrap::AddRange(
SocketAddressBlockListWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());

CHECK(args[0]->IsString());
CHECK(args[1]->IsString());
CHECK(args[2]->IsInt32());

sockaddr_storage address[2];
Utf8Value start(args.GetIsolate(), args[0]);
Utf8Value end(args.GetIsolate(), args[1]);
int32_t family;
if (!args[2]->Int32Value(env->context()).To(&family))
return;

if (!SocketAddress::ToSockAddr(family, *start, 0, &address[0]) ||
!SocketAddress::ToSockAddr(family, *end, 0, &address[1])) {
return;
}
CHECK(SocketAddressBase::HasInstance(env, args[0]));
CHECK(SocketAddressBase::HasInstance(env, args[1]));

SocketAddress start_addr(reinterpret_cast<const sockaddr*>(&address[0]));
SocketAddress end_addr(reinterpret_cast<const sockaddr*>(&address[1]));
SocketAddressBase* start_addr;
SocketAddressBase* end_addr;
ASSIGN_OR_RETURN_UNWRAP(&start_addr, args[0]);
ASSIGN_OR_RETURN_UNWRAP(&end_addr, args[1]);

// Starting address must come before the end address
if (start_addr > end_addr)
if (*start_addr->address().get() > *end_addr->address().get())
return args.GetReturnValue().Set(false);

wrap->blocklist_->AddSocketAddressRange(start_addr, end_addr);
wrap->blocklist_->AddSocketAddressRange(
start_addr->address(),
end_addr->address());

args.GetReturnValue().Set(true);
}
@@ -649,29 +633,22 @@ void SocketAddressBlockListWrap::AddSubnet(
SocketAddressBlockListWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());

CHECK(args[0]->IsString());
CHECK(SocketAddressBase::HasInstance(env, args[0]));
CHECK(args[1]->IsInt32());
CHECK(args[2]->IsInt32());

sockaddr_storage address;
Utf8Value network(args.GetIsolate(), args[0]);
int32_t family;
SocketAddressBase* addr;
ASSIGN_OR_RETURN_UNWRAP(&addr, args[0]);

int32_t prefix;
if (!args[1]->Int32Value(env->context()).To(&family) ||
!args[2]->Int32Value(env->context()).To(&prefix)) {
if (!args[1]->Int32Value(env->context()).To(&prefix)) {
return;
}

if (!SocketAddress::ToSockAddr(family, *network, 0, &address))
return;

CHECK_IMPLIES(family == AF_INET, prefix <= 32);
CHECK_IMPLIES(family == AF_INET6, prefix <= 128);
CHECK_IMPLIES(addr->address()->family() == AF_INET, prefix <= 32);
CHECK_IMPLIES(addr->address()->family() == AF_INET6, prefix <= 128);
CHECK_GE(prefix, 0);

wrap->blocklist_->AddSocketAddressMask(
SocketAddress(reinterpret_cast<const sockaddr*>(&address)),
prefix);
wrap->blocklist_->AddSocketAddressMask(addr->address(), prefix);

args.GetReturnValue().Set(true);
}
@@ -682,21 +659,11 @@ void SocketAddressBlockListWrap::Check(
SocketAddressBlockListWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());

CHECK(args[0]->IsString());
CHECK(args[1]->IsInt32());
CHECK(SocketAddressBase::HasInstance(env, args[0]));
SocketAddressBase* addr;
ASSIGN_OR_RETURN_UNWRAP(&addr, args[0]);

sockaddr_storage address;
Utf8Value value(args.GetIsolate(), args[0]);
int32_t family;
if (!args[1]->Int32Value(env->context()).To(&family))
return;

if (!SocketAddress::ToSockAddr(family, *value, 0, &address))
return;

args.GetReturnValue().Set(
wrap->blocklist_->Apply(
SocketAddress(reinterpret_cast<const sockaddr*>(&address))));
args.GetReturnValue().Set(wrap->blocklist_->Apply(addr->address()));
}

void SocketAddressBlockListWrap::GetRules(
@@ -869,7 +836,6 @@ void SocketAddressBase::Detail(const FunctionCallbackInfo<Value>& args) {
}

void SocketAddressBase::GetFlowLabel(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
SocketAddressBase* base;
ASSIGN_OR_RETURN_UNWRAP(&base, args.Holder());
args.GetReturnValue().Set(base->address_->flow_label());
42 changes: 22 additions & 20 deletions src/node_sockaddr.h
Original file line number Diff line number Diff line change
@@ -168,6 +168,10 @@ class SocketAddressBase : public BaseObject {
v8::Local<v8::Object> wrap,
std::shared_ptr<SocketAddress> address);

inline const std::shared_ptr<SocketAddress>& address() const {
return address_;
}

void MemoryInfo(MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(SocketAddressBase);
SET_SELF_SIZE(SocketAddressBase);
@@ -246,38 +250,36 @@ class SocketAddressBlockList : public MemoryRetainer {
std::shared_ptr<SocketAddressBlockList> parent = {});
~SocketAddressBlockList() = default;

void AddSocketAddress(
const SocketAddress& address);
void AddSocketAddress(const std::shared_ptr<SocketAddress>& address);

void RemoveSocketAddress(
const SocketAddress& address);
void RemoveSocketAddress(const std::shared_ptr<SocketAddress>& address);

void AddSocketAddressRange(
const SocketAddress& start,
const SocketAddress& end);
const std::shared_ptr<SocketAddress>& start,
const std::shared_ptr<SocketAddress>& end);

void AddSocketAddressMask(
const SocketAddress& address,
const std::shared_ptr<SocketAddress>& address,
int prefix);

bool Apply(const SocketAddress& address);
bool Apply(const std::shared_ptr<SocketAddress>& address);

size_t size() const { return rules_.size(); }

v8::MaybeLocal<v8::Array> ListRules(Environment* env);

struct Rule : public MemoryRetainer {
virtual bool Apply(const SocketAddress& address) = 0;
virtual bool Apply(const std::shared_ptr<SocketAddress>& address) = 0;
inline v8::MaybeLocal<v8::Value> ToV8String(Environment* env);
virtual std::string ToString() = 0;
};

struct SocketAddressRule final : Rule {
SocketAddress address;
std::shared_ptr<SocketAddress> address;

explicit SocketAddressRule(const SocketAddress& address);
explicit SocketAddressRule(const std::shared_ptr<SocketAddress>& address);

bool Apply(const SocketAddress& address) override;
bool Apply(const std::shared_ptr<SocketAddress>& address) override;
std::string ToString() override;

void MemoryInfo(node::MemoryTracker* tracker) const override;
@@ -286,14 +288,14 @@ class SocketAddressBlockList : public MemoryRetainer {
};

struct SocketAddressRangeRule final : Rule {
SocketAddress start;
SocketAddress end;
std::shared_ptr<SocketAddress> start;
std::shared_ptr<SocketAddress> end;

SocketAddressRangeRule(
const SocketAddress& start,
const SocketAddress& end);
const std::shared_ptr<SocketAddress>& start,
const std::shared_ptr<SocketAddress>& end);

bool Apply(const SocketAddress& address) override;
bool Apply(const std::shared_ptr<SocketAddress>& address) override;
std::string ToString() override;

void MemoryInfo(node::MemoryTracker* tracker) const override;
@@ -302,14 +304,14 @@ class SocketAddressBlockList : public MemoryRetainer {
};

struct SocketAddressMaskRule final : Rule {
SocketAddress network;
std::shared_ptr<SocketAddress> network;
int prefix;

SocketAddressMaskRule(
const SocketAddress& address,
const std::shared_ptr<SocketAddress>& address,
int prefix);

bool Apply(const SocketAddress& address) override;
bool Apply(const std::shared_ptr<SocketAddress>& address) override;
std::string ToString() override;

void MemoryInfo(node::MemoryTracker* tracker) const override;
8 changes: 6 additions & 2 deletions test/cctest/test_sockaddr.cc
Original file line number Diff line number Diff line change
@@ -197,8 +197,12 @@ TEST(SocketAddressBlockList, Simple) {
sockaddr_storage storage[2];
SocketAddress::ToSockAddr(AF_INET, "10.0.0.1", 0, &storage[0]);
SocketAddress::ToSockAddr(AF_INET, "10.0.0.2", 0, &storage[1]);
SocketAddress addr1(reinterpret_cast<const sockaddr*>(&storage[0]));
SocketAddress addr2(reinterpret_cast<const sockaddr*>(&storage[1]));
std::shared_ptr<SocketAddress> addr1 =
std::make_shared<SocketAddress>(
reinterpret_cast<const sockaddr*>(&storage[0]));
std::shared_ptr<SocketAddress> addr2 =
std::make_shared<SocketAddress>(
reinterpret_cast<const sockaddr*>(&storage[1]));

bl.AddSocketAddress(addr1);
bl.AddSocketAddress(addr2);
94 changes: 85 additions & 9 deletions test/parallel/test-blocklist.js
Original file line number Diff line number Diff line change
@@ -2,7 +2,10 @@

require('../common');

const { BlockList } = require('net');
const {
BlockList,
SocketAddress,
} = require('net');
const assert = require('assert');
const util = require('util');

@@ -65,6 +68,36 @@ const util = require('util');
assert(!blockList.check('::1', 'ipv6'));
}

{
const blockList = new BlockList();
const sa1 = new SocketAddress({ address: '1.1.1.1' });
const sa2 = new SocketAddress({
address: '8592:757c:efae:4e45:fb5d:d62a:0d00:8e17',
family: 'ipv6'
});
const sa3 = new SocketAddress({ address: '1.1.1.2' });

blockList.addAddress(sa1);
blockList.addAddress(sa2);
blockList.addAddress('::ffff:1.1.1.2', 'ipv6');

assert(blockList.check('1.1.1.1'));
assert(blockList.check(sa1));
assert(!blockList.check('1.1.1.1', 'ipv6'));
assert(!blockList.check('8592:757c:efae:4e45:fb5d:d62a:0d00:8e17'));
assert(blockList.check('8592:757c:efae:4e45:fb5d:d62a:0d00:8e17', 'ipv6'));
assert(blockList.check(sa2));

assert(blockList.check('::ffff:1.1.1.1', 'ipv6'));
assert(blockList.check('::ffff:1.1.1.1', 'IPV6'));

assert(blockList.check('1.1.1.2'));
assert(blockList.check(sa3));

assert(!blockList.check('1.2.3.4'));
assert(!blockList.check('::1', 'ipv6'));
}

{
const blockList = new BlockList();
blockList.addRange('1.1.1.1', '1.1.1.10');
@@ -83,6 +116,29 @@ const util = require('util');
assert(!blockList.check('::10', 'ipv6'));
}

{
const blockList = new BlockList();
const sa1 = new SocketAddress({ address: '1.1.1.1' });
const sa2 = new SocketAddress({ address: '1.1.1.10' });
const sa3 = new SocketAddress({ address: '::1', family: 'ipv6' });
const sa4 = new SocketAddress({ address: '::f', family: 'ipv6' });

blockList.addRange(sa1, sa2);
blockList.addRange(sa3, sa4);

assert(!blockList.check('1.1.1.0'));
for (let n = 1; n <= 10; n++)
assert(blockList.check(`1.1.1.${n}`));
assert(!blockList.check('1.1.1.11'));

assert(!blockList.check('::0', 'ipv6'));
for (let n = 0x1; n <= 0xf; n++) {
assert(blockList.check(`::${n.toString(16)}`, 'ipv6'),
`::${n.toString(16)} check failed`);
}
assert(!blockList.check('::10', 'ipv6'));
}

{
const blockList = new BlockList();
blockList.addSubnet('1.1.1.0', 16);
@@ -98,6 +154,23 @@ const util = require('util');
assert(!blockList.check('8592:757c:efae:4f45::f', 'ipv6'));
}

{
const blockList = new BlockList();
const sa1 = new SocketAddress({ address: '1.1.1.0' });
const sa2 = new SocketAddress({ address: '1.1.1.1' });
blockList.addSubnet(sa1, 16);
blockList.addSubnet('8592:757c:efae:4e45::', 64, 'ipv6');

assert(blockList.check('1.1.0.1'));
assert(blockList.check(sa2));
assert(!blockList.check('1.2.0.1'));
assert(blockList.check('::ffff:1.1.0.1', 'ipv6'));

assert(blockList.check('8592:757c:efae:4e45:f::', 'ipv6'));
assert(blockList.check('8592:757c:efae:4e45::f', 'ipv6'));
assert(!blockList.check('8592:757c:efae:4f45::f', 'ipv6'));
}

{
const blockList = new BlockList();
blockList.addAddress('1.1.1.1');
@@ -110,7 +183,6 @@ const util = require('util');
'Address: IPv4 1.1.1.1'
];
assert.deepStrictEqual(blockList.rules, rulesCheck);
console.log(blockList);

assert(blockList.check('1.1.1.1'));
assert(blockList.check('10.0.0.5'));
@@ -145,23 +217,27 @@ const util = require('util');
{
const blockList = new BlockList();
assert.throws(() => blockList.addSubnet(1), /ERR_INVALID_ARG_TYPE/);
assert.throws(() => blockList.addSubnet('', ''), /ERR_INVALID_ARG_TYPE/);
assert.throws(() => blockList.addSubnet('', NaN), /ERR_OUT_OF_RANGE/);
assert.throws(() => blockList.addSubnet('1.1.1.1', ''),
/ERR_INVALID_ARG_TYPE/);
assert.throws(() => blockList.addSubnet('1.1.1.1', NaN), /ERR_OUT_OF_RANGE/);
assert.throws(() => blockList.addSubnet('', 1, 1), /ERR_INVALID_ARG_TYPE/);
assert.throws(() => blockList.addSubnet('', 1, ''), /ERR_INVALID_ARG_VALUE/);

assert.throws(() => blockList.addSubnet('', -1, 'ipv4'), /ERR_OUT_OF_RANGE/);
assert.throws(() => blockList.addSubnet('', 33, 'ipv4'), /ERR_OUT_OF_RANGE/);
assert.throws(() => blockList.addSubnet('1.1.1.1', -1, 'ipv4'),
/ERR_OUT_OF_RANGE/);
assert.throws(() => blockList.addSubnet('1.1.1.1', 33, 'ipv4'),
/ERR_OUT_OF_RANGE/);

assert.throws(() => blockList.addSubnet('', -1, 'ipv6'), /ERR_OUT_OF_RANGE/);
assert.throws(() => blockList.addSubnet('', 129, 'ipv6'), /ERR_OUT_OF_RANGE/);
assert.throws(() => blockList.addSubnet('::', -1, 'ipv6'),
/ERR_OUT_OF_RANGE/);
assert.throws(() => blockList.addSubnet('::', 129, 'ipv6'),
/ERR_OUT_OF_RANGE/);
}

{
const blockList = new BlockList();
assert.throws(() => blockList.check(1), /ERR_INVALID_ARG_TYPE/);
assert.throws(() => blockList.check('', 1), /ERR_INVALID_ARG_TYPE/);
assert.throws(() => blockList.check('', ''), /ERR_INVALID_ARG_VALUE/);
}

{
1 change: 1 addition & 0 deletions tools/doc/type-parser.js
Original file line number Diff line number Diff line change
@@ -175,6 +175,7 @@ const customTypesMap = {
'net.BlockList': 'net.html#net_class_net_blocklist',
'net.Server': 'net.html#net_class_net_server',
'net.Socket': 'net.html#net_class_net_socket',
'net.SocketAddress': 'net.html#net_class_net_socketaddress',

'NodeEventTarget':
'events.html#events_class_nodeeventtarget',