Skip to content

Commit 4ec8d4b

Browse files
jasnelltargos
authored andcommitted
net: introduce net.BlockList
`net.BlockList` provides an object intended to be used by net APIs to specify rules for disallowing network activity with specific IP addresses. This commit adds the basic mechanism but does not add the specific uses. PR-URL: #34625 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Bradley Farias <[email protected]>
1 parent 6973a54 commit 4ec8d4b

File tree

10 files changed

+1189
-2
lines changed

10 files changed

+1189
-2
lines changed

‎doc/api/net.md‎

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,86 @@ net.createServer().listen(
5555
path.join('\\\\?\\pipe', process.cwd(), 'myctl'));
5656
```
5757

58+
## Class: `net.BlockList`
59+
<!-- YAML
60+
added: REPLACEME
61+
-->
62+
63+
The `BlockList` object can be used with some network APIs to specify rules for
64+
disabling inbound or outbound access to specific IP addresses, IP ranges, or
65+
IP subnets.
66+
67+
### `blockList.addAddress(address[, type])`
68+
<!-- YAML
69+
added: REPLACEME
70+
-->
71+
72+
*`address`{string} An IPv4 or IPv6 address.
73+
*`type`{string} Either `'ipv4'` or `'ipv6'`. **Default**: `'ipv4'`.
74+
75+
Adds a rule to block the given IP address.
76+
77+
### `blockList.addRange(start, end[, type])`
78+
<!-- YAML
79+
added: REPLACEME
80+
-->
81+
82+
*`start`{string} The starting IPv4 or IPv6 address in the range.
83+
*`end`{string} The ending IPv4 or IPv6 address in the range.
84+
*`type`{string} Either `'ipv4'` or `'ipv6'`. **Default**: `'ipv4'`.
85+
86+
Adds a rule to block a range of IP addresses from `start` (inclusive) to
87+
`end` (inclusive).
88+
89+
### `blockList.addSubnet(net, prefix[, type])`
90+
<!-- YAML
91+
added: REPLACEME
92+
-->
93+
94+
*`net`{string} The network IPv4 or IPv6 address.
95+
*`prefix`{number} The number of CIDR prefix bits. For IPv4, this
96+
must be a value between `0` and `32`. For IPv6, this must be between
97+
`0` and `128`.
98+
*`type`{string} Either `'ipv4'` or `'ipv6'`. **Default**: `'ipv4'`.
99+
100+
Adds a rule to block a range of IP addresses specified as a subnet mask.
101+
102+
### `blockList.check(address[, type])`
103+
<!-- YAML
104+
added: REPLACEME
105+
-->
106+
107+
*`address`{string} The IP address to check
108+
*`type`{string} Either `'ipv4'` or `'ipv6'`. **Default**: `'ipv4'`.
109+
* Returns:{boolean}
110+
111+
Returns `true` if the given IP address matches any of the rules added to the
112+
`BlockList`.
113+
114+
```js
115+
constblockList=newnet.BlockList();
116+
blockList.addAddress('123.123.123.123');
117+
blockList.addRange('10.0.0.1', '10.0.0.10');
118+
blockList.addSubnet('8592:757c:efae:4e45::', 64, 'ipv6');
119+
120+
console.log(blockList.check('123.123.123.123')); // Prints: true
121+
console.log(blockList.check('10.0.0.3')); // Prints: true
122+
console.log(blockList.check('222.111.111.222')); // Prints: false
123+
124+
// IPv6 notation for IPv4 addresses works:
125+
console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
126+
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
127+
```
128+
129+
### `blockList.rules`
130+
<!-- YAML
131+
added: REPLACEME
132+
-->
133+
134+
* Type:{string[]}
135+
136+
The list of rules added to the blocklist.
137+
58138
## Class: `net.Server`
59139
<!-- YAML
60140
added: v0.1.90

‎lib/internal/blocklist.js‎

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
'use strict';
2+
3+
const{
4+
Boolean,
5+
Symbol
6+
}=primordials;
7+
8+
const{
9+
BlockList: BlockListHandle,
10+
AF_INET,
11+
AF_INET6,
12+
}=internalBinding('block_list');
13+
14+
const{
15+
customInspectSymbol: kInspect,
16+
}=require('internal/util');
17+
const{ inspect }=require('internal/util/inspect');
18+
19+
constkHandle=Symbol('kHandle');
20+
const{ owner_symbol }=internalBinding('symbols');
21+
22+
const{
23+
ERR_INVALID_ARG_TYPE,
24+
ERR_INVALID_ARG_VALUE,
25+
ERR_OUT_OF_RANGE,
26+
}=require('internal/errors').codes;
27+
28+
classBlockList{
29+
constructor(){
30+
this[kHandle]=newBlockListHandle();
31+
this[kHandle][owner_symbol]=this;
32+
}
33+
34+
[kInspect](depth,options){
35+
if(depth<0)
36+
returnthis;
37+
38+
constopts={
39+
...options,
40+
depth: options.depth==null ? null : options.depth-1
41+
};
42+
43+
return`BlockList ${inspect({
44+
rules: this.rules
45+
},opts)}`;
46+
}
47+
48+
addAddress(address,family='ipv4'){
49+
if(typeofaddress!=='string')
50+
thrownewERR_INVALID_ARG_TYPE('address','string',address);
51+
if(typeoffamily!=='string')
52+
thrownewERR_INVALID_ARG_TYPE('family','string',family);
53+
if(family!=='ipv4'&&family!=='ipv6')
54+
thrownewERR_INVALID_ARG_VALUE('family',family);
55+
consttype=family==='ipv4' ? AF_INET : AF_INET6;
56+
this[kHandle].addAddress(address,type);
57+
}
58+
59+
addRange(start,end,family='ipv4'){
60+
if(typeofstart!=='string')
61+
thrownewERR_INVALID_ARG_TYPE('start','string',start);
62+
if(typeofend!=='string')
63+
thrownewERR_INVALID_ARG_TYPE('end','string',end);
64+
if(typeoffamily!=='string')
65+
thrownewERR_INVALID_ARG_TYPE('family','string',family);
66+
if(family!=='ipv4'&&family!=='ipv6')
67+
thrownewERR_INVALID_ARG_VALUE('family',family);
68+
consttype=family==='ipv4' ? AF_INET : AF_INET6;
69+
constret=this[kHandle].addRange(start,end,type);
70+
if(ret===false)
71+
thrownewERR_INVALID_ARG_VALUE('start',start,'must come before end');
72+
}
73+
74+
addSubnet(network,prefix,family='ipv4'){
75+
if(typeofnetwork!=='string')
76+
thrownewERR_INVALID_ARG_TYPE('network','string',network);
77+
if(typeofprefix!=='number')
78+
thrownewERR_INVALID_ARG_TYPE('prefix','number',prefix);
79+
if(typeoffamily!=='string')
80+
thrownewERR_INVALID_ARG_TYPE('family','string',family);
81+
lettype;
82+
switch(family){
83+
case'ipv4':
84+
type=AF_INET;
85+
if(prefix<0||prefix>32)
86+
thrownewERR_OUT_OF_RANGE(prefix,'>= 0 and <= 32',prefix);
87+
break;
88+
case'ipv6':
89+
type=AF_INET6;
90+
if(prefix<0||prefix>128)
91+
thrownewERR_OUT_OF_RANGE(prefix,'>= 0 and <= 128',prefix);
92+
break;
93+
default:
94+
thrownewERR_INVALID_ARG_VALUE('family',family);
95+
}
96+
this[kHandle].addSubnet(network,type,prefix);
97+
}
98+
99+
check(address,family='ipv4'){
100+
if(typeofaddress!=='string')
101+
thrownewERR_INVALID_ARG_TYPE('address','string',address);
102+
if(typeoffamily!=='string')
103+
thrownewERR_INVALID_ARG_TYPE('family','string',family);
104+
if(family!=='ipv4'&&family!=='ipv6')
105+
thrownewERR_INVALID_ARG_VALUE('family',family);
106+
consttype=family==='ipv4' ? AF_INET : AF_INET6;
107+
returnBoolean(this[kHandle].check(address,type));
108+
}
109+
110+
getrules(){
111+
returnthis[kHandle].getRules();
112+
}
113+
}
114+
115+
module.exports=BlockList;

‎lib/net.js‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ const{
115115
// Lazy loaded to improve startup performance.
116116
letcluster;
117117
letdns;
118+
letBlockList;
118119

119120
const{ clearTimeout }=require('timers');
120121
const{ kTimeout }=require('internal/timers');
@@ -1755,6 +1756,11 @@ module.exports ={
17551756
_createServerHandle: createServerHandle,
17561757
_normalizeArgs: normalizeArgs,
17571758
_setSimultaneousAccepts,
1759+
getBlockList(){
1760+
if(BlockList===undefined)
1761+
BlockList=require('internal/blocklist');
1762+
returnBlockList;
1763+
},
17581764
connect,
17591765
createConnection: connect,
17601766
createServer,

‎node.gyp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
'lib/internal/assert/assertion_error.js',
102102
'lib/internal/assert/calltracker.js',
103103
'lib/internal/async_hooks.js',
104+
'lib/internal/blocklist.js',
104105
'lib/internal/buffer.js',
105106
'lib/internal/cli_table.js',
106107
'lib/internal/child_process.js',

‎src/node_binding.cc‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
// __attribute__((constructor)) like mechanism in GCC.
3838
#defineNODE_BUILTIN_STANDARD_MODULES(V) \
3939
V(async_wrap) \
40+
V(block_list) \
4041
V(buffer) \
4142
V(cares_wrap) \
4243
V(config) \

‎src/node_sockaddr-inl.h‎

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

66
#include"node.h"
7+
#include"env-inl.h"
78
#include"node_internals.h"
89
#include"node_sockaddr.h"
910
#include"util-inl.h"
@@ -88,11 +89,11 @@ SocketAddress& SocketAddress::operator=(const SocketAddress& addr){
8889
}
8990

9091
const sockaddr& SocketAddress::operator*() const{
91-
return *this->data();
92+
return *data();
9293
}
9394

9495
const sockaddr* SocketAddress::operator->() const{
95-
returnthis->data();
96+
returndata();
9697
}
9798

9899
size_tSocketAddress::length() const{
@@ -166,6 +167,24 @@ bool SocketAddress::operator!=(const SocketAddress& other) const{
166167
return !(*this == other);
167168
}
168169

170+
bool SocketAddress::operator<(const SocketAddress& other) const{
171+
returncompare(other) == CompareResult::LESS_THAN;
172+
}
173+
174+
bool SocketAddress::operator>(const SocketAddress& other) const{
175+
returncompare(other) == CompareResult::GREATER_THAN;
176+
}
177+
178+
bool SocketAddress::operator<=(const SocketAddress& other) const{
179+
CompareResult c = compare(other);
180+
return c == CompareResult::NOT_COMPARABLE ? false :
181+
c <= CompareResult::SAME;
182+
}
183+
184+
bool SocketAddress::operator>=(const SocketAddress& other) const{
185+
returncompare(other) >= CompareResult::SAME;
186+
}
187+
169188
template <typename T>
170189
SocketAddressLRU<T>::SocketAddressLRU(
171190
size_t max_size)
@@ -231,6 +250,11 @@ typename T::Type* SocketAddressLRU<T>::Upsert(
231250
return &map_[address]->second;
232251
}
233252

253+
v8::MaybeLocal<v8::Value> SocketAddressBlockList::Rule::ToV8String(
254+
Environment* env){
255+
std::string str = ToString();
256+
returnToV8Value(env->context(), str);
257+
}
234258
} // namespace node
235259

236260
#endif// NODE_WANT_INTERNALS

0 commit comments

Comments
(0)