Skip to content

Commit

Permalink
net: allow net.BlockList to use net.SocketAddress objects
Browse files Browse the repository at this point in the history
Signed-off-by: James M Snell <jasnell@gmail.com>

PR-URL: nodejs#37917
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
jasnell authored and foxxyz committed Oct 18, 2021
1 parent 6a0cad2 commit 5993eda
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 162 deletions.
17 changes: 9 additions & 8 deletions doc/api/net.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ IP subnets.
added: REPLACEME
-->

* `address` {string} An IPv4 or IPv6 address.
* `type` {string} Either `'ipv4'` or `'ipv6'`. **Default**: `'ipv4'`.
* `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.

Expand All @@ -79,9 +79,10 @@ Adds a rule to block the given IP address.
added: REPLACEME
-->

* `start` {string} The starting IPv4 or IPv6 address in the range.
* `end` {string} The ending IPv4 or IPv6 address in the range.
* `type` {string} Either `'ipv4'` or `'ipv6'`. **Default**: `'ipv4'`.
* `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
`end` (inclusive).
Expand All @@ -91,7 +92,7 @@ Adds a rule to block a range of IP addresses from `start` (inclusive) to
added: REPLACEME
-->

* `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`.
Expand All @@ -104,8 +105,8 @@ Adds a rule to block a range of IP addresses specified as a subnet mask.
added: REPLACEME
-->

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

Returns `true` if the given IP address matches any of the rules added to the
Expand Down
91 changes: 57 additions & 34 deletions lib/internal/blocklist.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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() {
Expand Down
7 changes: 5 additions & 2 deletions lib/internal/socketaddress.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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');
Expand Down Expand Up @@ -150,4 +152,5 @@ ObjectSetPrototypeOf(InternalSocketAddress.prototype, SocketAddress.prototype);
module.exports = {
SocketAddress,
InternalSocketAddress,
kHandle,
};
Loading

0 comments on commit 5993eda

Please sign in to comment.