Commit 3d7d277

Browse files
jasnelladuh95
authored andcommitted
net: improve performance of net.BlockList
* fix duplicate address insertion in SocketAddressBlockList * fix BlockList rule listing order to match apply * add minor bound check in BlockList * improve performance of BlockList apply * eliminating shared_ptr * check fast api path * add clear method to BlockList * general storage improvements to BlockList * use shared locks for BlockList reads * add bulk address adding to BlockList * add BlockList benchmark * add remove range/subnet to BlockList * add cidr notation parsing to BlockList * add additional apis to BlockList * add private subnet presets to BlockList Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: OpenCode/Opus PR-URL: #64974 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
1 parent e9327d1 commit 3d7d277

8 files changed

Lines changed: 2061 additions & 127 deletions

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
'use strict';
2+
3+
constcommon=require('../common.js');
4+
const{ BlockList, SocketAddress }=require('net');
5+
6+
consthasAddAddresses=typeofBlockList.prototype.addAddresses==='function';
7+
8+
constoperations=['check','checkWithSocketAddress','addAddress'];
9+
if(hasAddAddresses){
10+
operations.push('addAddresses');
11+
}
12+
13+
constbench=common.createBenchmark(main,{
14+
n: [1e6],
15+
ruleCount: [10,100,1000,10000],
16+
ruleType: ['address','subnet','mixed'],
17+
checkResult: ['hit','miss'],
18+
operation: operations,
19+
},{
20+
combinationFilter({ operation, ruleCount, ruleType }){
21+
// addAddress and addAddresses only need address rules, not subnets.
22+
if((operation==='addAddress'||operation==='addAddresses')&&
23+
ruleType!=='address'){
24+
returnfalse;
25+
}
26+
returntrue;
27+
},
28+
});
29+
30+
functiongenerateIPv4(index){
31+
return`${(index>>>24)&0xff}.${(index>>>16)&0xff}.`+
32+
`${(index>>>8)&0xff}.${index&0xff}`;
33+
}
34+
35+
functionbuildBlockList(ruleCount,ruleType){
36+
constblockList=newBlockList();
37+
38+
if(ruleType==='address'||ruleType==='mixed'){
39+
constaddressCount=ruleType==='mixed' ?
40+
Math.floor(ruleCount/2) : ruleCount;
41+
constaddresses=[];
42+
for(leti=0;i<addressCount;i++){
43+
// Start from 10.0.0.1 to avoid 0.0.0.0
44+
addresses.push(generateIPv4(0x0a000001+i));
45+
}
46+
if(hasAddAddresses){
47+
blockList.addAddresses(addresses);
48+
}else{
49+
for(constaddrofaddresses){
50+
blockList.addAddress(addr);
51+
}
52+
}
53+
}
54+
55+
if(ruleType==='subnet'||ruleType==='mixed'){
56+
constsubnetCount=ruleType==='mixed' ?
57+
Math.floor(ruleCount/2) : ruleCount;
58+
for(leti=0;i<subnetCount;i++){
59+
// Use distinct /24 subnets: 172.i.j.0/24
60+
constsecond=(i>>>8)&0xff;
61+
constthird=i&0xff;
62+
blockList.addSubnet(`172.${second}.${third}.0`,24);
63+
}
64+
}
65+
66+
returnblockList;
67+
}
68+
69+
functionmain({ n, ruleCount, ruleType, checkResult, operation }){
70+
if(operation==='check'){
71+
benchCheck(n,ruleCount,ruleType,checkResult);
72+
}elseif(operation==='checkWithSocketAddress'){
73+
benchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult);
74+
}elseif(operation==='addAddress'){
75+
benchAddAddress(n,ruleCount);
76+
}elseif(operation==='addAddresses'){
77+
benchAddAddresses(n,ruleCount);
78+
}
79+
}
80+
81+
// Benchmark check() with string addresses (the common JS API path).
82+
functionbenchCheck(n,ruleCount,ruleType,checkResult){
83+
constblockList=buildBlockList(ruleCount,ruleType);
84+
85+
// For 'hit', use an address that's in the list.
86+
// For 'miss', use an address that's not in the list.
87+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
88+
89+
bench.start();
90+
for(leti=0;i<n;i++){
91+
blockList.check(address);
92+
}
93+
bench.end(n);
94+
}
95+
96+
// Benchmark check() with pre-created SocketAddress objects
97+
// (avoids measuring SocketAddress construction overhead).
98+
functionbenchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult){
99+
constblockList=buildBlockList(ruleCount,ruleType);
100+
101+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
102+
constsa=newSocketAddress({ address });
103+
104+
bench.start();
105+
for(leti=0;i<n;i++){
106+
blockList.check(sa);
107+
}
108+
bench.end(n);
109+
}
110+
111+
// Benchmark single addAddress() calls (one lock acquire per call).
112+
functionbenchAddAddress(n,ruleCount){
113+
// Scale n down for large rule counts to keep runtime reasonable.
114+
constiterations=Math.min(n,ruleCount*100);
115+
116+
constaddresses=[];
117+
for(leti=0;i<ruleCount;i++){
118+
addresses.push(generateIPv4(0x0a000001+i));
119+
}
120+
121+
bench.start();
122+
for(leti=0;i<iterations;i++){
123+
constblockList=newBlockList();
124+
for(letj=0;j<addresses.length;j++){
125+
blockList.addAddress(addresses[j]);
126+
}
127+
}
128+
bench.end(iterations);
129+
}
130+
131+
// Benchmark batch addAddresses() (one lock acquire per batch).
132+
functionbenchAddAddresses(n,ruleCount){
133+
constiterations=Math.min(n,ruleCount*100);
134+
135+
constaddresses=[];
136+
for(leti=0;i<ruleCount;i++){
137+
addresses.push(generateIPv4(0x0a000001+i));
138+
}
139+
140+
bench.start();
141+
for(leti=0;i<iterations;i++){
142+
constblockList=newBlockList();
143+
blockList.addAddresses(addresses);
144+
}
145+
bench.end(iterations);
146+
}

β€Ždoc/api/net.mdβ€Ž

Lines changed: 169 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,47 @@ added:
9696

9797
Adds a rule to block the given IP address.
9898

99+
### `blockList.addAddresses(addresses[, type])`
100+
101+
<!-- YAML
102+
added: REPLACEME
103+
-->
104+
105+
*`addresses` {string\[]|net.SocketAddress\[]} An array of IPv4 or IPv6
106+
addresses.
107+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
108+
109+
Adds multiple address rules to the block list in a single operation.
110+
This is more efficient than calling `blockList.addAddress()` repeatedly
111+
when adding a large number of individual addresses, as the addresses
112+
are inserted under a single internal lock acquisition.
113+
114+
### `blockList.addCIDR(cidr)`
115+
116+
<!-- YAML
117+
added: REPLACEME
118+
-->
119+
120+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
121+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
122+
123+
Adds a subnet rule using CIDR notation. The address family is automatically
124+
detected from the address (IPv6 if the address contains `':'`, IPv4
125+
otherwise). This is equivalent to calling `blockList.addSubnet()` with
126+
the parsed network address, prefix length, and family.
127+
128+
### `blockList.addCIDRs(cidrs)`
129+
130+
<!-- YAML
131+
added: REPLACEME
132+
-->
133+
134+
*`cidrs` {string\[]} An array of IPv4 or IPv6 subnets in CIDR notation.
135+
136+
Adds multiple subnet rules using CIDR notation in a single call. The address
137+
family for each entry is automatically detected. This is equivalent to
138+
calling `blockList.addCIDR()` for each element of the array.
139+
99140
### `blockList.addRange(start, end[, type])`
100141

101142
<!-- YAML
@@ -158,28 +199,13 @@ console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
158199
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
159200
```
160201

161-
### `blockList.rules`
202+
### `blockList.clear()`
162203

163-
<!-- YAML
164-
added:
165-
- v15.0.0
166-
- v14.18.0
204+
<!--
205+
added: REPLACEME
167206
-->
168207

169-
* Type: {string\[]}
170-
171-
The list of rules added to the blocklist.
172-
173-
### `BlockList.isBlockList(value)`
174-
175-
<!-- YAML
176-
added:
177-
- v23.4.0
178-
- v22.13.0
179-
-->
180-
181-
*`value` {any} Any JS value
182-
* Returns `true` if the `value` is a `net.BlockList`.
208+
Clears all rules from the `BlockList`.
183209

184210
### `blockList.fromJSON(value)`
185211

@@ -205,6 +231,130 @@ blockList.fromJSON(JSON.stringify(data));
205231

206232
*`value` Blocklist.rules
207233

234+
### `BlockList.isBlockList(value)`
235+
236+
<!-- YAML
237+
added:
238+
- v23.4.0
239+
- v22.13.0
240+
-->
241+
242+
*`value` {any} Any JS value
243+
* Returns `true` if the `value` is a `net.BlockList`.
244+
245+
### `BlockList.PRIVATE_RANGES`
246+
247+
<!-- YAML
248+
added: REPLACEME
249+
-->
250+
251+
* Type: {string\[]}
252+
253+
A frozen array of CIDR strings representing private, loopback, and link-local
254+
IP address ranges. This can be passed to `blockList.addCIDRs()` to quickly
255+
populate a blocklist with all non-routable address ranges.
256+
257+
The included ranges are:
258+
259+
*`10.0.0.0/8` β€” RFC 1918 private IPv4
260+
*`172.16.0.0/12` β€” RFC 1918 private IPv4
261+
*`192.168.0.0/16` β€” RFC 1918 private IPv4
262+
*`127.0.0.0/8` β€” IPv4 loopback
263+
*`::1/128` β€” IPv6 loopback
264+
*`169.254.0.0/16` β€” IPv4 link-local
265+
*`fe80::/10` β€” IPv6 link-local
266+
*`fc00::/7` β€” IPv6 unique local (ULA)
267+
268+
```js
269+
constblockList=newnet.BlockList();
270+
blockList.addCIDRs(net.BlockList.PRIVATE_RANGES);
271+
272+
console.log(blockList.check('10.0.0.1')); // Prints: true
273+
console.log(blockList.check('127.0.0.1')); // Prints: true
274+
console.log(blockList.check('8.8.8.8')); // Prints: false
275+
```
276+
277+
### `blockList.removeAddress(address[, type])`
278+
279+
<!-- YAML
280+
added: REPLACEME
281+
-->
282+
283+
*`address` {string|net.SocketAddress} An IPv4 or IPv6 address.
284+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
285+
286+
Removes a rule that was previously added with `blockList.addAddress()`. The
287+
address must match exactly the value used when the rule was added. If the
288+
specified address does not exist, this is a no-op.
289+
290+
### `blockList.removeCIDR(cidr)`
291+
292+
<!-- YAML
293+
added: REPLACEME
294+
-->
295+
296+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
297+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
298+
299+
Removes a subnet rule using CIDR notation. The address family is automatically
300+
detected from the address. This is equivalent to calling
301+
`blockList.removeSubnet()` with the parsed network address, prefix length,
302+
and family. If the specified subnet does not exist, this is a no-op.
303+
304+
### `blockList.removeRange(start, end[, type])`
305+
306+
<!-- YAML
307+
added: REPLACEME
308+
-->
309+
310+
*`start` {string|net.SocketAddress} The starting IPv4 or IPv6 address in the
311+
range.
312+
*`end` {string|net.SocketAddress} The ending IPv4 or IPv6 address in the range.
313+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
314+
315+
Removes a rule that was previously added with `blockList.addRange()`. The `start`
316+
and `end` addresses must match exactly the values used when the rule was added.
317+
If the specified range does not exist, this is a no-op.
318+
319+
### `blockList.removeSubnet(net, prefix[, type])`
320+
321+
<!-- YAML
322+
added: REPLACEME
323+
-->
324+
325+
*`net` {string|net.SocketAddress} The network IPv4 or IPv6 address.
326+
*`prefix` {number} The number of CIDR prefix bits. For IPv4, this
327+
must be a value between `0` and `32`. For IPv6, this must be between
328+
`0` and `128`.
329+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
330+
331+
Removes a rule that was previously added with `blockList.addSubnet()`. The
332+
network address and prefix must match exactly the values used when the rule was
333+
added. If the specified subnet does not exist, this is a no-op.
334+
335+
### `blockList.rules`
336+
337+
<!-- YAML
338+
added:
339+
- v15.0.0
340+
- v14.18.0
341+
-->
342+
343+
* Type: {string\[]}
344+
345+
The list of rules added to the blocklist.
346+
347+
### `blockList.size`
348+
349+
<!-- YAML
350+
added: REPLACEME
351+
-->
352+
353+
* Type: {number}
354+
355+
The number of rules in the blocklist. This is equivalent to
356+
`blockList.rules.length` but does not allocate the rules array.
357+
208358
### `blockList.toJSON()`
209359

210360
> Stability: 1.2 - Release candidate

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Commit 3d7d277

Browse files
jasnelladuh95
authored andcommitted
net: improve performance of net.BlockList
* fix duplicate address insertion in SocketAddressBlockList * fix BlockList rule listing order to match apply * add minor bound check in BlockList * improve performance of BlockList apply * eliminating shared_ptr * check fast api path * add clear method to BlockList * general storage improvements to BlockList * use shared locks for BlockList reads * add bulk address adding to BlockList * add BlockList benchmark * add remove range/subnet to BlockList * add cidr notation parsing to BlockList * add additional apis to BlockList * add private subnet presets to BlockList Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: OpenCode/Opus PR-URL: #64974 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
1 parent e9327d1 commit 3d7d277

8 files changed

Lines changed: 2061 additions & 127 deletions

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
'use strict';
2+
3+
constcommon=require('../common.js');
4+
const{ BlockList, SocketAddress }=require('net');
5+
6+
consthasAddAddresses=typeofBlockList.prototype.addAddresses==='function';
7+
8+
constoperations=['check','checkWithSocketAddress','addAddress'];
9+
if(hasAddAddresses){
10+
operations.push('addAddresses');
11+
}
12+
13+
constbench=common.createBenchmark(main,{
14+
n: [1e6],
15+
ruleCount: [10,100,1000,10000],
16+
ruleType: ['address','subnet','mixed'],
17+
checkResult: ['hit','miss'],
18+
operation: operations,
19+
},{
20+
combinationFilter({ operation, ruleCount, ruleType }){
21+
// addAddress and addAddresses only need address rules, not subnets.
22+
if((operation==='addAddress'||operation==='addAddresses')&&
23+
ruleType!=='address'){
24+
returnfalse;
25+
}
26+
returntrue;
27+
},
28+
});
29+
30+
functiongenerateIPv4(index){
31+
return`${(index>>>24)&0xff}.${(index>>>16)&0xff}.`+
32+
`${(index>>>8)&0xff}.${index&0xff}`;
33+
}
34+
35+
functionbuildBlockList(ruleCount,ruleType){
36+
constblockList=newBlockList();
37+
38+
if(ruleType==='address'||ruleType==='mixed'){
39+
constaddressCount=ruleType==='mixed' ?
40+
Math.floor(ruleCount/2) : ruleCount;
41+
constaddresses=[];
42+
for(leti=0;i<addressCount;i++){
43+
// Start from 10.0.0.1 to avoid 0.0.0.0
44+
addresses.push(generateIPv4(0x0a000001+i));
45+
}
46+
if(hasAddAddresses){
47+
blockList.addAddresses(addresses);
48+
}else{
49+
for(constaddrofaddresses){
50+
blockList.addAddress(addr);
51+
}
52+
}
53+
}
54+
55+
if(ruleType==='subnet'||ruleType==='mixed'){
56+
constsubnetCount=ruleType==='mixed' ?
57+
Math.floor(ruleCount/2) : ruleCount;
58+
for(leti=0;i<subnetCount;i++){
59+
// Use distinct /24 subnets: 172.i.j.0/24
60+
constsecond=(i>>>8)&0xff;
61+
constthird=i&0xff;
62+
blockList.addSubnet(`172.${second}.${third}.0`,24);
63+
}
64+
}
65+
66+
returnblockList;
67+
}
68+
69+
functionmain({ n, ruleCount, ruleType, checkResult, operation }){
70+
if(operation==='check'){
71+
benchCheck(n,ruleCount,ruleType,checkResult);
72+
}elseif(operation==='checkWithSocketAddress'){
73+
benchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult);
74+
}elseif(operation==='addAddress'){
75+
benchAddAddress(n,ruleCount);
76+
}elseif(operation==='addAddresses'){
77+
benchAddAddresses(n,ruleCount);
78+
}
79+
}
80+
81+
// Benchmark check() with string addresses (the common JS API path).
82+
functionbenchCheck(n,ruleCount,ruleType,checkResult){
83+
constblockList=buildBlockList(ruleCount,ruleType);
84+
85+
// For 'hit', use an address that's in the list.
86+
// For 'miss', use an address that's not in the list.
87+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
88+
89+
bench.start();
90+
for(leti=0;i<n;i++){
91+
blockList.check(address);
92+
}
93+
bench.end(n);
94+
}
95+
96+
// Benchmark check() with pre-created SocketAddress objects
97+
// (avoids measuring SocketAddress construction overhead).
98+
functionbenchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult){
99+
constblockList=buildBlockList(ruleCount,ruleType);
100+
101+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
102+
constsa=newSocketAddress({ address });
103+
104+
bench.start();
105+
for(leti=0;i<n;i++){
106+
blockList.check(sa);
107+
}
108+
bench.end(n);
109+
}
110+
111+
// Benchmark single addAddress() calls (one lock acquire per call).
112+
functionbenchAddAddress(n,ruleCount){
113+
// Scale n down for large rule counts to keep runtime reasonable.
114+
constiterations=Math.min(n,ruleCount*100);
115+
116+
constaddresses=[];
117+
for(leti=0;i<ruleCount;i++){
118+
addresses.push(generateIPv4(0x0a000001+i));
119+
}
120+
121+
bench.start();
122+
for(leti=0;i<iterations;i++){
123+
constblockList=newBlockList();
124+
for(letj=0;j<addresses.length;j++){
125+
blockList.addAddress(addresses[j]);
126+
}
127+
}
128+
bench.end(iterations);
129+
}
130+
131+
// Benchmark batch addAddresses() (one lock acquire per batch).
132+
functionbenchAddAddresses(n,ruleCount){
133+
constiterations=Math.min(n,ruleCount*100);
134+
135+
constaddresses=[];
136+
for(leti=0;i<ruleCount;i++){
137+
addresses.push(generateIPv4(0x0a000001+i));
138+
}
139+
140+
bench.start();
141+
for(leti=0;i<iterations;i++){
142+
constblockList=newBlockList();
143+
blockList.addAddresses(addresses);
144+
}
145+
bench.end(iterations);
146+
}

β€Ždoc/api/net.mdβ€Ž

Lines changed: 169 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,47 @@ added:
9696

9797
Adds a rule to block the given IP address.
9898

99+
### `blockList.addAddresses(addresses[, type])`
100+
101+
<!-- YAML
102+
added: REPLACEME
103+
-->
104+
105+
*`addresses` {string\[]|net.SocketAddress\[]} An array of IPv4 or IPv6
106+
addresses.
107+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
108+
109+
Adds multiple address rules to the block list in a single operation.
110+
This is more efficient than calling `blockList.addAddress()` repeatedly
111+
when adding a large number of individual addresses, as the addresses
112+
are inserted under a single internal lock acquisition.
113+
114+
### `blockList.addCIDR(cidr)`
115+
116+
<!-- YAML
117+
added: REPLACEME
118+
-->
119+
120+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
121+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
122+
123+
Adds a subnet rule using CIDR notation. The address family is automatically
124+
detected from the address (IPv6 if the address contains `':'`, IPv4
125+
otherwise). This is equivalent to calling `blockList.addSubnet()` with
126+
the parsed network address, prefix length, and family.
127+
128+
### `blockList.addCIDRs(cidrs)`
129+
130+
<!-- YAML
131+
added: REPLACEME
132+
-->
133+
134+
*`cidrs` {string\[]} An array of IPv4 or IPv6 subnets in CIDR notation.
135+
136+
Adds multiple subnet rules using CIDR notation in a single call. The address
137+
family for each entry is automatically detected. This is equivalent to
138+
calling `blockList.addCIDR()` for each element of the array.
139+
99140
### `blockList.addRange(start, end[, type])`
100141

101142
<!-- YAML
@@ -158,28 +199,13 @@ console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
158199
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
159200
```
160201

161-
### `blockList.rules`
202+
### `blockList.clear()`
162203

163-
<!-- YAML
164-
added:
165-
- v15.0.0
166-
- v14.18.0
204+
<!--
205+
added: REPLACEME
167206
-->
168207

169-
* Type: {string\[]}
170-
171-
The list of rules added to the blocklist.
172-
173-
### `BlockList.isBlockList(value)`
174-
175-
<!-- YAML
176-
added:
177-
- v23.4.0
178-
- v22.13.0
179-
-->
180-
181-
*`value` {any} Any JS value
182-
* Returns `true` if the `value` is a `net.BlockList`.
208+
Clears all rules from the `BlockList`.
183209

184210
### `blockList.fromJSON(value)`
185211

@@ -205,6 +231,130 @@ blockList.fromJSON(JSON.stringify(data));
205231

206232
*`value` Blocklist.rules
207233

234+
### `BlockList.isBlockList(value)`
235+
236+
<!-- YAML
237+
added:
238+
- v23.4.0
239+
- v22.13.0
240+
-->
241+
242+
*`value` {any} Any JS value
243+
* Returns `true` if the `value` is a `net.BlockList`.
244+
245+
### `BlockList.PRIVATE_RANGES`
246+
247+
<!-- YAML
248+
added: REPLACEME
249+
-->
250+
251+
* Type: {string\[]}
252+
253+
A frozen array of CIDR strings representing private, loopback, and link-local
254+
IP address ranges. This can be passed to `blockList.addCIDRs()` to quickly
255+
populate a blocklist with all non-routable address ranges.
256+
257+
The included ranges are:
258+
259+
*`10.0.0.0/8` β€” RFC 1918 private IPv4
260+
*`172.16.0.0/12` β€” RFC 1918 private IPv4
261+
*`192.168.0.0/16` β€” RFC 1918 private IPv4
262+
*`127.0.0.0/8` β€” IPv4 loopback
263+
*`::1/128` β€” IPv6 loopback
264+
*`169.254.0.0/16` β€” IPv4 link-local
265+
*`fe80::/10` β€” IPv6 link-local
266+
*`fc00::/7` β€” IPv6 unique local (ULA)
267+
268+
```js
269+
constblockList=newnet.BlockList();
270+
blockList.addCIDRs(net.BlockList.PRIVATE_RANGES);
271+
272+
console.log(blockList.check('10.0.0.1')); // Prints: true
273+
console.log(blockList.check('127.0.0.1')); // Prints: true
274+
console.log(blockList.check('8.8.8.8')); // Prints: false
275+
```
276+
277+
### `blockList.removeAddress(address[, type])`
278+
279+
<!-- YAML
280+
added: REPLACEME
281+
-->
282+
283+
*`address` {string|net.SocketAddress} An IPv4 or IPv6 address.
284+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
285+
286+
Removes a rule that was previously added with `blockList.addAddress()`. The
287+
address must match exactly the value used when the rule was added. If the
288+
specified address does not exist, this is a no-op.
289+
290+
### `blockList.removeCIDR(cidr)`
291+
292+
<!-- YAML
293+
added: REPLACEME
294+
-->
295+
296+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
297+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
298+
299+
Removes a subnet rule using CIDR notation. The address family is automatically
300+
detected from the address. This is equivalent to calling
301+
`blockList.removeSubnet()` with the parsed network address, prefix length,
302+
and family. If the specified subnet does not exist, this is a no-op.
303+
304+
### `blockList.removeRange(start, end[, type])`
305+
306+
<!-- YAML
307+
added: REPLACEME
308+
-->
309+
310+
*`start` {string|net.SocketAddress} The starting IPv4 or IPv6 address in the
311+
range.
312+
*`end` {string|net.SocketAddress} The ending IPv4 or IPv6 address in the range.
313+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
314+
315+
Removes a rule that was previously added with `blockList.addRange()`. The `start`
316+
and `end` addresses must match exactly the values used when the rule was added.
317+
If the specified range does not exist, this is a no-op.
318+
319+
### `blockList.removeSubnet(net, prefix[, type])`
320+
321+
<!-- YAML
322+
added: REPLACEME
323+
-->
324+
325+
*`net` {string|net.SocketAddress} The network IPv4 or IPv6 address.
326+
*`prefix` {number} The number of CIDR prefix bits. For IPv4, this
327+
must be a value between `0` and `32`. For IPv6, this must be between
328+
`0` and `128`.
329+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
330+
331+
Removes a rule that was previously added with `blockList.addSubnet()`. The
332+
network address and prefix must match exactly the values used when the rule was
333+
added. If the specified subnet does not exist, this is a no-op.
334+
335+
### `blockList.rules`
336+
337+
<!-- YAML
338+
added:
339+
- v15.0.0
340+
- v14.18.0
341+
-->
342+
343+
* Type: {string\[]}
344+
345+
The list of rules added to the blocklist.
346+
347+
### `blockList.size`
348+
349+
<!-- YAML
350+
added: REPLACEME
351+
-->
352+
353+
* Type: {number}
354+
355+
The number of rules in the blocklist. This is equivalent to
356+
`blockList.rules.length` but does not allocate the rules array.
357+
208358
### `blockList.toJSON()`
209359

210360
> Stability: 1.2 - Release candidate

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 3d7d277

Browse files
jasnelladuh95
authored andcommitted
net: improve performance of net.BlockList
* fix duplicate address insertion in SocketAddressBlockList * fix BlockList rule listing order to match apply * add minor bound check in BlockList * improve performance of BlockList apply * eliminating shared_ptr * check fast api path * add clear method to BlockList * general storage improvements to BlockList * use shared locks for BlockList reads * add bulk address adding to BlockList * add BlockList benchmark * add remove range/subnet to BlockList * add cidr notation parsing to BlockList * add additional apis to BlockList * add private subnet presets to BlockList Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: OpenCode/Opus PR-URL: #64974 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
1 parent e9327d1 commit 3d7d277

8 files changed

Lines changed: 2061 additions & 127 deletions

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
'use strict';
2+
3+
constcommon=require('../common.js');
4+
const{ BlockList, SocketAddress }=require('net');
5+
6+
consthasAddAddresses=typeofBlockList.prototype.addAddresses==='function';
7+
8+
constoperations=['check','checkWithSocketAddress','addAddress'];
9+
if(hasAddAddresses){
10+
operations.push('addAddresses');
11+
}
12+
13+
constbench=common.createBenchmark(main,{
14+
n: [1e6],
15+
ruleCount: [10,100,1000,10000],
16+
ruleType: ['address','subnet','mixed'],
17+
checkResult: ['hit','miss'],
18+
operation: operations,
19+
},{
20+
combinationFilter({ operation, ruleCount, ruleType }){
21+
// addAddress and addAddresses only need address rules, not subnets.
22+
if((operation==='addAddress'||operation==='addAddresses')&&
23+
ruleType!=='address'){
24+
returnfalse;
25+
}
26+
returntrue;
27+
},
28+
});
29+
30+
functiongenerateIPv4(index){
31+
return`${(index>>>24)&0xff}.${(index>>>16)&0xff}.`+
32+
`${(index>>>8)&0xff}.${index&0xff}`;
33+
}
34+
35+
functionbuildBlockList(ruleCount,ruleType){
36+
constblockList=newBlockList();
37+
38+
if(ruleType==='address'||ruleType==='mixed'){
39+
constaddressCount=ruleType==='mixed' ?
40+
Math.floor(ruleCount/2) : ruleCount;
41+
constaddresses=[];
42+
for(leti=0;i<addressCount;i++){
43+
// Start from 10.0.0.1 to avoid 0.0.0.0
44+
addresses.push(generateIPv4(0x0a000001+i));
45+
}
46+
if(hasAddAddresses){
47+
blockList.addAddresses(addresses);
48+
}else{
49+
for(constaddrofaddresses){
50+
blockList.addAddress(addr);
51+
}
52+
}
53+
}
54+
55+
if(ruleType==='subnet'||ruleType==='mixed'){
56+
constsubnetCount=ruleType==='mixed' ?
57+
Math.floor(ruleCount/2) : ruleCount;
58+
for(leti=0;i<subnetCount;i++){
59+
// Use distinct /24 subnets: 172.i.j.0/24
60+
constsecond=(i>>>8)&0xff;
61+
constthird=i&0xff;
62+
blockList.addSubnet(`172.${second}.${third}.0`,24);
63+
}
64+
}
65+
66+
returnblockList;
67+
}
68+
69+
functionmain({ n, ruleCount, ruleType, checkResult, operation }){
70+
if(operation==='check'){
71+
benchCheck(n,ruleCount,ruleType,checkResult);
72+
}elseif(operation==='checkWithSocketAddress'){
73+
benchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult);
74+
}elseif(operation==='addAddress'){
75+
benchAddAddress(n,ruleCount);
76+
}elseif(operation==='addAddresses'){
77+
benchAddAddresses(n,ruleCount);
78+
}
79+
}
80+
81+
// Benchmark check() with string addresses (the common JS API path).
82+
functionbenchCheck(n,ruleCount,ruleType,checkResult){
83+
constblockList=buildBlockList(ruleCount,ruleType);
84+
85+
// For 'hit', use an address that's in the list.
86+
// For 'miss', use an address that's not in the list.
87+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
88+
89+
bench.start();
90+
for(leti=0;i<n;i++){
91+
blockList.check(address);
92+
}
93+
bench.end(n);
94+
}
95+
96+
// Benchmark check() with pre-created SocketAddress objects
97+
// (avoids measuring SocketAddress construction overhead).
98+
functionbenchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult){
99+
constblockList=buildBlockList(ruleCount,ruleType);
100+
101+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
102+
constsa=newSocketAddress({ address });
103+
104+
bench.start();
105+
for(leti=0;i<n;i++){
106+
blockList.check(sa);
107+
}
108+
bench.end(n);
109+
}
110+
111+
// Benchmark single addAddress() calls (one lock acquire per call).
112+
functionbenchAddAddress(n,ruleCount){
113+
// Scale n down for large rule counts to keep runtime reasonable.
114+
constiterations=Math.min(n,ruleCount*100);
115+
116+
constaddresses=[];
117+
for(leti=0;i<ruleCount;i++){
118+
addresses.push(generateIPv4(0x0a000001+i));
119+
}
120+
121+
bench.start();
122+
for(leti=0;i<iterations;i++){
123+
constblockList=newBlockList();
124+
for(letj=0;j<addresses.length;j++){
125+
blockList.addAddress(addresses[j]);
126+
}
127+
}
128+
bench.end(iterations);
129+
}
130+
131+
// Benchmark batch addAddresses() (one lock acquire per batch).
132+
functionbenchAddAddresses(n,ruleCount){
133+
constiterations=Math.min(n,ruleCount*100);
134+
135+
constaddresses=[];
136+
for(leti=0;i<ruleCount;i++){
137+
addresses.push(generateIPv4(0x0a000001+i));
138+
}
139+
140+
bench.start();
141+
for(leti=0;i<iterations;i++){
142+
constblockList=newBlockList();
143+
blockList.addAddresses(addresses);
144+
}
145+
bench.end(iterations);
146+
}

β€Ždoc/api/net.mdβ€Ž

Lines changed: 169 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,47 @@ added:
9696

9797
Adds a rule to block the given IP address.
9898

99+
### `blockList.addAddresses(addresses[, type])`
100+
101+
<!-- YAML
102+
added: REPLACEME
103+
-->
104+
105+
*`addresses` {string\[]|net.SocketAddress\[]} An array of IPv4 or IPv6
106+
addresses.
107+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
108+
109+
Adds multiple address rules to the block list in a single operation.
110+
This is more efficient than calling `blockList.addAddress()` repeatedly
111+
when adding a large number of individual addresses, as the addresses
112+
are inserted under a single internal lock acquisition.
113+
114+
### `blockList.addCIDR(cidr)`
115+
116+
<!-- YAML
117+
added: REPLACEME
118+
-->
119+
120+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
121+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
122+
123+
Adds a subnet rule using CIDR notation. The address family is automatically
124+
detected from the address (IPv6 if the address contains `':'`, IPv4
125+
otherwise). This is equivalent to calling `blockList.addSubnet()` with
126+
the parsed network address, prefix length, and family.
127+
128+
### `blockList.addCIDRs(cidrs)`
129+
130+
<!-- YAML
131+
added: REPLACEME
132+
-->
133+
134+
*`cidrs` {string\[]} An array of IPv4 or IPv6 subnets in CIDR notation.
135+
136+
Adds multiple subnet rules using CIDR notation in a single call. The address
137+
family for each entry is automatically detected. This is equivalent to
138+
calling `blockList.addCIDR()` for each element of the array.
139+
99140
### `blockList.addRange(start, end[, type])`
100141

101142
<!-- YAML
@@ -158,28 +199,13 @@ console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
158199
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
159200
```
160201

161-
### `blockList.rules`
202+
### `blockList.clear()`
162203

163-
<!-- YAML
164-
added:
165-
- v15.0.0
166-
- v14.18.0
204+
<!--
205+
added: REPLACEME
167206
-->
168207

169-
* Type: {string\[]}
170-
171-
The list of rules added to the blocklist.
172-
173-
### `BlockList.isBlockList(value)`
174-
175-
<!-- YAML
176-
added:
177-
- v23.4.0
178-
- v22.13.0
179-
-->
180-
181-
*`value` {any} Any JS value
182-
* Returns `true` if the `value` is a `net.BlockList`.
208+
Clears all rules from the `BlockList`.
183209

184210
### `blockList.fromJSON(value)`
185211

@@ -205,6 +231,130 @@ blockList.fromJSON(JSON.stringify(data));
205231

206232
*`value` Blocklist.rules
207233

234+
### `BlockList.isBlockList(value)`
235+
236+
<!-- YAML
237+
added:
238+
- v23.4.0
239+
- v22.13.0
240+
-->
241+
242+
*`value` {any} Any JS value
243+
* Returns `true` if the `value` is a `net.BlockList`.
244+
245+
### `BlockList.PRIVATE_RANGES`
246+
247+
<!-- YAML
248+
added: REPLACEME
249+
-->
250+
251+
* Type: {string\[]}
252+
253+
A frozen array of CIDR strings representing private, loopback, and link-local
254+
IP address ranges. This can be passed to `blockList.addCIDRs()` to quickly
255+
populate a blocklist with all non-routable address ranges.
256+
257+
The included ranges are:
258+
259+
*`10.0.0.0/8` β€” RFC 1918 private IPv4
260+
*`172.16.0.0/12` β€” RFC 1918 private IPv4
261+
*`192.168.0.0/16` β€” RFC 1918 private IPv4
262+
*`127.0.0.0/8` β€” IPv4 loopback
263+
*`::1/128` β€” IPv6 loopback
264+
*`169.254.0.0/16` β€” IPv4 link-local
265+
*`fe80::/10` β€” IPv6 link-local
266+
*`fc00::/7` β€” IPv6 unique local (ULA)
267+
268+
```js
269+
constblockList=newnet.BlockList();
270+
blockList.addCIDRs(net.BlockList.PRIVATE_RANGES);
271+
272+
console.log(blockList.check('10.0.0.1')); // Prints: true
273+
console.log(blockList.check('127.0.0.1')); // Prints: true
274+
console.log(blockList.check('8.8.8.8')); // Prints: false
275+
```
276+
277+
### `blockList.removeAddress(address[, type])`
278+
279+
<!-- YAML
280+
added: REPLACEME
281+
-->
282+
283+
*`address` {string|net.SocketAddress} An IPv4 or IPv6 address.
284+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
285+
286+
Removes a rule that was previously added with `blockList.addAddress()`. The
287+
address must match exactly the value used when the rule was added. If the
288+
specified address does not exist, this is a no-op.
289+
290+
### `blockList.removeCIDR(cidr)`
291+
292+
<!-- YAML
293+
added: REPLACEME
294+
-->
295+
296+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
297+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
298+
299+
Removes a subnet rule using CIDR notation. The address family is automatically
300+
detected from the address. This is equivalent to calling
301+
`blockList.removeSubnet()` with the parsed network address, prefix length,
302+
and family. If the specified subnet does not exist, this is a no-op.
303+
304+
### `blockList.removeRange(start, end[, type])`
305+
306+
<!-- YAML
307+
added: REPLACEME
308+
-->
309+
310+
*`start` {string|net.SocketAddress} The starting IPv4 or IPv6 address in the
311+
range.
312+
*`end` {string|net.SocketAddress} The ending IPv4 or IPv6 address in the range.
313+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
314+
315+
Removes a rule that was previously added with `blockList.addRange()`. The `start`
316+
and `end` addresses must match exactly the values used when the rule was added.
317+
If the specified range does not exist, this is a no-op.
318+
319+
### `blockList.removeSubnet(net, prefix[, type])`
320+
321+
<!-- YAML
322+
added: REPLACEME
323+
-->
324+
325+
*`net` {string|net.SocketAddress} The network IPv4 or IPv6 address.
326+
*`prefix` {number} The number of CIDR prefix bits. For IPv4, this
327+
must be a value between `0` and `32`. For IPv6, this must be between
328+
`0` and `128`.
329+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
330+
331+
Removes a rule that was previously added with `blockList.addSubnet()`. The
332+
network address and prefix must match exactly the values used when the rule was
333+
added. If the specified subnet does not exist, this is a no-op.
334+
335+
### `blockList.rules`
336+
337+
<!-- YAML
338+
added:
339+
- v15.0.0
340+
- v14.18.0
341+
-->
342+
343+
* Type: {string\[]}
344+
345+
The list of rules added to the blocklist.
346+
347+
### `blockList.size`
348+
349+
<!-- YAML
350+
added: REPLACEME
351+
-->
352+
353+
* Type: {number}
354+
355+
The number of rules in the blocklist. This is equivalent to
356+
`blockList.rules.length` but does not allocate the rules array.
357+
208358
### `blockList.toJSON()`
209359

210360
> Stability: 1.2 - Release candidate

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 3d7d277

Browse files
jasnelladuh95
authored andcommitted
net: improve performance of net.BlockList
* fix duplicate address insertion in SocketAddressBlockList * fix BlockList rule listing order to match apply * add minor bound check in BlockList * improve performance of BlockList apply * eliminating shared_ptr * check fast api path * add clear method to BlockList * general storage improvements to BlockList * use shared locks for BlockList reads * add bulk address adding to BlockList * add BlockList benchmark * add remove range/subnet to BlockList * add cidr notation parsing to BlockList * add additional apis to BlockList * add private subnet presets to BlockList Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: OpenCode/Opus PR-URL: #64974 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
1 parent e9327d1 commit 3d7d277

8 files changed

Lines changed: 2061 additions & 127 deletions

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
'use strict';
2+
3+
constcommon=require('../common.js');
4+
const{ BlockList, SocketAddress }=require('net');
5+
6+
consthasAddAddresses=typeofBlockList.prototype.addAddresses==='function';
7+
8+
constoperations=['check','checkWithSocketAddress','addAddress'];
9+
if(hasAddAddresses){
10+
operations.push('addAddresses');
11+
}
12+
13+
constbench=common.createBenchmark(main,{
14+
n: [1e6],
15+
ruleCount: [10,100,1000,10000],
16+
ruleType: ['address','subnet','mixed'],
17+
checkResult: ['hit','miss'],
18+
operation: operations,
19+
},{
20+
combinationFilter({ operation, ruleCount, ruleType }){
21+
// addAddress and addAddresses only need address rules, not subnets.
22+
if((operation==='addAddress'||operation==='addAddresses')&&
23+
ruleType!=='address'){
24+
returnfalse;
25+
}
26+
returntrue;
27+
},
28+
});
29+
30+
functiongenerateIPv4(index){
31+
return`${(index>>>24)&0xff}.${(index>>>16)&0xff}.`+
32+
`${(index>>>8)&0xff}.${index&0xff}`;
33+
}
34+
35+
functionbuildBlockList(ruleCount,ruleType){
36+
constblockList=newBlockList();
37+
38+
if(ruleType==='address'||ruleType==='mixed'){
39+
constaddressCount=ruleType==='mixed' ?
40+
Math.floor(ruleCount/2) : ruleCount;
41+
constaddresses=[];
42+
for(leti=0;i<addressCount;i++){
43+
// Start from 10.0.0.1 to avoid 0.0.0.0
44+
addresses.push(generateIPv4(0x0a000001+i));
45+
}
46+
if(hasAddAddresses){
47+
blockList.addAddresses(addresses);
48+
}else{
49+
for(constaddrofaddresses){
50+
blockList.addAddress(addr);
51+
}
52+
}
53+
}
54+
55+
if(ruleType==='subnet'||ruleType==='mixed'){
56+
constsubnetCount=ruleType==='mixed' ?
57+
Math.floor(ruleCount/2) : ruleCount;
58+
for(leti=0;i<subnetCount;i++){
59+
// Use distinct /24 subnets: 172.i.j.0/24
60+
constsecond=(i>>>8)&0xff;
61+
constthird=i&0xff;
62+
blockList.addSubnet(`172.${second}.${third}.0`,24);
63+
}
64+
}
65+
66+
returnblockList;
67+
}
68+
69+
functionmain({ n, ruleCount, ruleType, checkResult, operation }){
70+
if(operation==='check'){
71+
benchCheck(n,ruleCount,ruleType,checkResult);
72+
}elseif(operation==='checkWithSocketAddress'){
73+
benchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult);
74+
}elseif(operation==='addAddress'){
75+
benchAddAddress(n,ruleCount);
76+
}elseif(operation==='addAddresses'){
77+
benchAddAddresses(n,ruleCount);
78+
}
79+
}
80+
81+
// Benchmark check() with string addresses (the common JS API path).
82+
functionbenchCheck(n,ruleCount,ruleType,checkResult){
83+
constblockList=buildBlockList(ruleCount,ruleType);
84+
85+
// For 'hit', use an address that's in the list.
86+
// For 'miss', use an address that's not in the list.
87+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
88+
89+
bench.start();
90+
for(leti=0;i<n;i++){
91+
blockList.check(address);
92+
}
93+
bench.end(n);
94+
}
95+
96+
// Benchmark check() with pre-created SocketAddress objects
97+
// (avoids measuring SocketAddress construction overhead).
98+
functionbenchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult){
99+
constblockList=buildBlockList(ruleCount,ruleType);
100+
101+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
102+
constsa=newSocketAddress({ address });
103+
104+
bench.start();
105+
for(leti=0;i<n;i++){
106+
blockList.check(sa);
107+
}
108+
bench.end(n);
109+
}
110+
111+
// Benchmark single addAddress() calls (one lock acquire per call).
112+
functionbenchAddAddress(n,ruleCount){
113+
// Scale n down for large rule counts to keep runtime reasonable.
114+
constiterations=Math.min(n,ruleCount*100);
115+
116+
constaddresses=[];
117+
for(leti=0;i<ruleCount;i++){
118+
addresses.push(generateIPv4(0x0a000001+i));
119+
}
120+
121+
bench.start();
122+
for(leti=0;i<iterations;i++){
123+
constblockList=newBlockList();
124+
for(letj=0;j<addresses.length;j++){
125+
blockList.addAddress(addresses[j]);
126+
}
127+
}
128+
bench.end(iterations);
129+
}
130+
131+
// Benchmark batch addAddresses() (one lock acquire per batch).
132+
functionbenchAddAddresses(n,ruleCount){
133+
constiterations=Math.min(n,ruleCount*100);
134+
135+
constaddresses=[];
136+
for(leti=0;i<ruleCount;i++){
137+
addresses.push(generateIPv4(0x0a000001+i));
138+
}
139+
140+
bench.start();
141+
for(leti=0;i<iterations;i++){
142+
constblockList=newBlockList();
143+
blockList.addAddresses(addresses);
144+
}
145+
bench.end(iterations);
146+
}

β€Ždoc/api/net.mdβ€Ž

Lines changed: 169 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,47 @@ added:
9696

9797
Adds a rule to block the given IP address.
9898

99+
### `blockList.addAddresses(addresses[, type])`
100+
101+
<!-- YAML
102+
added: REPLACEME
103+
-->
104+
105+
*`addresses` {string\[]|net.SocketAddress\[]} An array of IPv4 or IPv6
106+
addresses.
107+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
108+
109+
Adds multiple address rules to the block list in a single operation.
110+
This is more efficient than calling `blockList.addAddress()` repeatedly
111+
when adding a large number of individual addresses, as the addresses
112+
are inserted under a single internal lock acquisition.
113+
114+
### `blockList.addCIDR(cidr)`
115+
116+
<!-- YAML
117+
added: REPLACEME
118+
-->
119+
120+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
121+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
122+
123+
Adds a subnet rule using CIDR notation. The address family is automatically
124+
detected from the address (IPv6 if the address contains `':'`, IPv4
125+
otherwise). This is equivalent to calling `blockList.addSubnet()` with
126+
the parsed network address, prefix length, and family.
127+
128+
### `blockList.addCIDRs(cidrs)`
129+
130+
<!-- YAML
131+
added: REPLACEME
132+
-->
133+
134+
*`cidrs` {string\[]} An array of IPv4 or IPv6 subnets in CIDR notation.
135+
136+
Adds multiple subnet rules using CIDR notation in a single call. The address
137+
family for each entry is automatically detected. This is equivalent to
138+
calling `blockList.addCIDR()` for each element of the array.
139+
99140
### `blockList.addRange(start, end[, type])`
100141

101142
<!-- YAML
@@ -158,28 +199,13 @@ console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
158199
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
159200
```
160201

161-
### `blockList.rules`
202+
### `blockList.clear()`
162203

163-
<!-- YAML
164-
added:
165-
- v15.0.0
166-
- v14.18.0
204+
<!--
205+
added: REPLACEME
167206
-->
168207

169-
* Type: {string\[]}
170-
171-
The list of rules added to the blocklist.
172-
173-
### `BlockList.isBlockList(value)`
174-
175-
<!-- YAML
176-
added:
177-
- v23.4.0
178-
- v22.13.0
179-
-->
180-
181-
*`value` {any} Any JS value
182-
* Returns `true` if the `value` is a `net.BlockList`.
208+
Clears all rules from the `BlockList`.
183209

184210
### `blockList.fromJSON(value)`
185211

@@ -205,6 +231,130 @@ blockList.fromJSON(JSON.stringify(data));
205231

206232
*`value` Blocklist.rules
207233

234+
### `BlockList.isBlockList(value)`
235+
236+
<!-- YAML
237+
added:
238+
- v23.4.0
239+
- v22.13.0
240+
-->
241+
242+
*`value` {any} Any JS value
243+
* Returns `true` if the `value` is a `net.BlockList`.
244+
245+
### `BlockList.PRIVATE_RANGES`
246+
247+
<!-- YAML
248+
added: REPLACEME
249+
-->
250+
251+
* Type: {string\[]}
252+
253+
A frozen array of CIDR strings representing private, loopback, and link-local
254+
IP address ranges. This can be passed to `blockList.addCIDRs()` to quickly
255+
populate a blocklist with all non-routable address ranges.
256+
257+
The included ranges are:
258+
259+
*`10.0.0.0/8` β€” RFC 1918 private IPv4
260+
*`172.16.0.0/12` β€” RFC 1918 private IPv4
261+
*`192.168.0.0/16` β€” RFC 1918 private IPv4
262+
*`127.0.0.0/8` β€” IPv4 loopback
263+
*`::1/128` β€” IPv6 loopback
264+
*`169.254.0.0/16` β€” IPv4 link-local
265+
*`fe80::/10` β€” IPv6 link-local
266+
*`fc00::/7` β€” IPv6 unique local (ULA)
267+
268+
```js
269+
constblockList=newnet.BlockList();
270+
blockList.addCIDRs(net.BlockList.PRIVATE_RANGES);
271+
272+
console.log(blockList.check('10.0.0.1')); // Prints: true
273+
console.log(blockList.check('127.0.0.1')); // Prints: true
274+
console.log(blockList.check('8.8.8.8')); // Prints: false
275+
```
276+
277+
### `blockList.removeAddress(address[, type])`
278+
279+
<!-- YAML
280+
added: REPLACEME
281+
-->
282+
283+
*`address` {string|net.SocketAddress} An IPv4 or IPv6 address.
284+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
285+
286+
Removes a rule that was previously added with `blockList.addAddress()`. The
287+
address must match exactly the value used when the rule was added. If the
288+
specified address does not exist, this is a no-op.
289+
290+
### `blockList.removeCIDR(cidr)`
291+
292+
<!-- YAML
293+
added: REPLACEME
294+
-->
295+
296+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
297+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
298+
299+
Removes a subnet rule using CIDR notation. The address family is automatically
300+
detected from the address. This is equivalent to calling
301+
`blockList.removeSubnet()` with the parsed network address, prefix length,
302+
and family. If the specified subnet does not exist, this is a no-op.
303+
304+
### `blockList.removeRange(start, end[, type])`
305+
306+
<!-- YAML
307+
added: REPLACEME
308+
-->
309+
310+
*`start` {string|net.SocketAddress} The starting IPv4 or IPv6 address in the
311+
range.
312+
*`end` {string|net.SocketAddress} The ending IPv4 or IPv6 address in the range.
313+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
314+
315+
Removes a rule that was previously added with `blockList.addRange()`. The `start`
316+
and `end` addresses must match exactly the values used when the rule was added.
317+
If the specified range does not exist, this is a no-op.
318+
319+
### `blockList.removeSubnet(net, prefix[, type])`
320+
321+
<!-- YAML
322+
added: REPLACEME
323+
-->
324+
325+
*`net` {string|net.SocketAddress} The network IPv4 or IPv6 address.
326+
*`prefix` {number} The number of CIDR prefix bits. For IPv4, this
327+
must be a value between `0` and `32`. For IPv6, this must be between
328+
`0` and `128`.
329+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
330+
331+
Removes a rule that was previously added with `blockList.addSubnet()`. The
332+
network address and prefix must match exactly the values used when the rule was
333+
added. If the specified subnet does not exist, this is a no-op.
334+
335+
### `blockList.rules`
336+
337+
<!-- YAML
338+
added:
339+
- v15.0.0
340+
- v14.18.0
341+
-->
342+
343+
* Type: {string\[]}
344+
345+
The list of rules added to the blocklist.
346+
347+
### `blockList.size`
348+
349+
<!-- YAML
350+
added: REPLACEME
351+
-->
352+
353+
* Type: {number}
354+
355+
The number of rules in the blocklist. This is equivalent to
356+
`blockList.rules.length` but does not allocate the rules array.
357+
208358
### `blockList.toJSON()`
209359

210360
> Stability: 1.2 - Release candidate

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Commit 3d7d277

Browse files
jasnelladuh95
authored andcommitted
net: improve performance of net.BlockList
* fix duplicate address insertion in SocketAddressBlockList * fix BlockList rule listing order to match apply * add minor bound check in BlockList * improve performance of BlockList apply * eliminating shared_ptr * check fast api path * add clear method to BlockList * general storage improvements to BlockList * use shared locks for BlockList reads * add bulk address adding to BlockList * add BlockList benchmark * add remove range/subnet to BlockList * add cidr notation parsing to BlockList * add additional apis to BlockList * add private subnet presets to BlockList Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: OpenCode/Opus PR-URL: #64974 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
1 parent e9327d1 commit 3d7d277

8 files changed

Lines changed: 2061 additions & 127 deletions

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
'use strict';
2+
3+
constcommon=require('../common.js');
4+
const{ BlockList, SocketAddress }=require('net');
5+
6+
consthasAddAddresses=typeofBlockList.prototype.addAddresses==='function';
7+
8+
constoperations=['check','checkWithSocketAddress','addAddress'];
9+
if(hasAddAddresses){
10+
operations.push('addAddresses');
11+
}
12+
13+
constbench=common.createBenchmark(main,{
14+
n: [1e6],
15+
ruleCount: [10,100,1000,10000],
16+
ruleType: ['address','subnet','mixed'],
17+
checkResult: ['hit','miss'],
18+
operation: operations,
19+
},{
20+
combinationFilter({ operation, ruleCount, ruleType }){
21+
// addAddress and addAddresses only need address rules, not subnets.
22+
if((operation==='addAddress'||operation==='addAddresses')&&
23+
ruleType!=='address'){
24+
returnfalse;
25+
}
26+
returntrue;
27+
},
28+
});
29+
30+
functiongenerateIPv4(index){
31+
return`${(index>>>24)&0xff}.${(index>>>16)&0xff}.`+
32+
`${(index>>>8)&0xff}.${index&0xff}`;
33+
}
34+
35+
functionbuildBlockList(ruleCount,ruleType){
36+
constblockList=newBlockList();
37+
38+
if(ruleType==='address'||ruleType==='mixed'){
39+
constaddressCount=ruleType==='mixed' ?
40+
Math.floor(ruleCount/2) : ruleCount;
41+
constaddresses=[];
42+
for(leti=0;i<addressCount;i++){
43+
// Start from 10.0.0.1 to avoid 0.0.0.0
44+
addresses.push(generateIPv4(0x0a000001+i));
45+
}
46+
if(hasAddAddresses){
47+
blockList.addAddresses(addresses);
48+
}else{
49+
for(constaddrofaddresses){
50+
blockList.addAddress(addr);
51+
}
52+
}
53+
}
54+
55+
if(ruleType==='subnet'||ruleType==='mixed'){
56+
constsubnetCount=ruleType==='mixed' ?
57+
Math.floor(ruleCount/2) : ruleCount;
58+
for(leti=0;i<subnetCount;i++){
59+
// Use distinct /24 subnets: 172.i.j.0/24
60+
constsecond=(i>>>8)&0xff;
61+
constthird=i&0xff;
62+
blockList.addSubnet(`172.${second}.${third}.0`,24);
63+
}
64+
}
65+
66+
returnblockList;
67+
}
68+
69+
functionmain({ n, ruleCount, ruleType, checkResult, operation }){
70+
if(operation==='check'){
71+
benchCheck(n,ruleCount,ruleType,checkResult);
72+
}elseif(operation==='checkWithSocketAddress'){
73+
benchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult);
74+
}elseif(operation==='addAddress'){
75+
benchAddAddress(n,ruleCount);
76+
}elseif(operation==='addAddresses'){
77+
benchAddAddresses(n,ruleCount);
78+
}
79+
}
80+
81+
// Benchmark check() with string addresses (the common JS API path).
82+
functionbenchCheck(n,ruleCount,ruleType,checkResult){
83+
constblockList=buildBlockList(ruleCount,ruleType);
84+
85+
// For 'hit', use an address that's in the list.
86+
// For 'miss', use an address that's not in the list.
87+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
88+
89+
bench.start();
90+
for(leti=0;i<n;i++){
91+
blockList.check(address);
92+
}
93+
bench.end(n);
94+
}
95+
96+
// Benchmark check() with pre-created SocketAddress objects
97+
// (avoids measuring SocketAddress construction overhead).
98+
functionbenchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult){
99+
constblockList=buildBlockList(ruleCount,ruleType);
100+
101+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
102+
constsa=newSocketAddress({ address });
103+
104+
bench.start();
105+
for(leti=0;i<n;i++){
106+
blockList.check(sa);
107+
}
108+
bench.end(n);
109+
}
110+
111+
// Benchmark single addAddress() calls (one lock acquire per call).
112+
functionbenchAddAddress(n,ruleCount){
113+
// Scale n down for large rule counts to keep runtime reasonable.
114+
constiterations=Math.min(n,ruleCount*100);
115+
116+
constaddresses=[];
117+
for(leti=0;i<ruleCount;i++){
118+
addresses.push(generateIPv4(0x0a000001+i));
119+
}
120+
121+
bench.start();
122+
for(leti=0;i<iterations;i++){
123+
constblockList=newBlockList();
124+
for(letj=0;j<addresses.length;j++){
125+
blockList.addAddress(addresses[j]);
126+
}
127+
}
128+
bench.end(iterations);
129+
}
130+
131+
// Benchmark batch addAddresses() (one lock acquire per batch).
132+
functionbenchAddAddresses(n,ruleCount){
133+
constiterations=Math.min(n,ruleCount*100);
134+
135+
constaddresses=[];
136+
for(leti=0;i<ruleCount;i++){
137+
addresses.push(generateIPv4(0x0a000001+i));
138+
}
139+
140+
bench.start();
141+
for(leti=0;i<iterations;i++){
142+
constblockList=newBlockList();
143+
blockList.addAddresses(addresses);
144+
}
145+
bench.end(iterations);
146+
}

β€Ždoc/api/net.mdβ€Ž

Lines changed: 169 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,47 @@ added:
9696

9797
Adds a rule to block the given IP address.
9898

99+
### `blockList.addAddresses(addresses[, type])`
100+
101+
<!-- YAML
102+
added: REPLACEME
103+
-->
104+
105+
*`addresses` {string\[]|net.SocketAddress\[]} An array of IPv4 or IPv6
106+
addresses.
107+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
108+
109+
Adds multiple address rules to the block list in a single operation.
110+
This is more efficient than calling `blockList.addAddress()` repeatedly
111+
when adding a large number of individual addresses, as the addresses
112+
are inserted under a single internal lock acquisition.
113+
114+
### `blockList.addCIDR(cidr)`
115+
116+
<!-- YAML
117+
added: REPLACEME
118+
-->
119+
120+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
121+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
122+
123+
Adds a subnet rule using CIDR notation. The address family is automatically
124+
detected from the address (IPv6 if the address contains `':'`, IPv4
125+
otherwise). This is equivalent to calling `blockList.addSubnet()` with
126+
the parsed network address, prefix length, and family.
127+
128+
### `blockList.addCIDRs(cidrs)`
129+
130+
<!-- YAML
131+
added: REPLACEME
132+
-->
133+
134+
*`cidrs` {string\[]} An array of IPv4 or IPv6 subnets in CIDR notation.
135+
136+
Adds multiple subnet rules using CIDR notation in a single call. The address
137+
family for each entry is automatically detected. This is equivalent to
138+
calling `blockList.addCIDR()` for each element of the array.
139+
99140
### `blockList.addRange(start, end[, type])`
100141

101142
<!-- YAML
@@ -158,28 +199,13 @@ console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
158199
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
159200
```
160201

161-
### `blockList.rules`
202+
### `blockList.clear()`
162203

163-
<!-- YAML
164-
added:
165-
- v15.0.0
166-
- v14.18.0
204+
<!--
205+
added: REPLACEME
167206
-->
168207

169-
* Type: {string\[]}
170-
171-
The list of rules added to the blocklist.
172-
173-
### `BlockList.isBlockList(value)`
174-
175-
<!-- YAML
176-
added:
177-
- v23.4.0
178-
- v22.13.0
179-
-->
180-
181-
*`value` {any} Any JS value
182-
* Returns `true` if the `value` is a `net.BlockList`.
208+
Clears all rules from the `BlockList`.
183209

184210
### `blockList.fromJSON(value)`
185211

@@ -205,6 +231,130 @@ blockList.fromJSON(JSON.stringify(data));
205231

206232
*`value` Blocklist.rules
207233

234+
### `BlockList.isBlockList(value)`
235+
236+
<!-- YAML
237+
added:
238+
- v23.4.0
239+
- v22.13.0
240+
-->
241+
242+
*`value` {any} Any JS value
243+
* Returns `true` if the `value` is a `net.BlockList`.
244+
245+
### `BlockList.PRIVATE_RANGES`
246+
247+
<!-- YAML
248+
added: REPLACEME
249+
-->
250+
251+
* Type: {string\[]}
252+
253+
A frozen array of CIDR strings representing private, loopback, and link-local
254+
IP address ranges. This can be passed to `blockList.addCIDRs()` to quickly
255+
populate a blocklist with all non-routable address ranges.
256+
257+
The included ranges are:
258+
259+
*`10.0.0.0/8` β€” RFC 1918 private IPv4
260+
*`172.16.0.0/12` β€” RFC 1918 private IPv4
261+
*`192.168.0.0/16` β€” RFC 1918 private IPv4
262+
*`127.0.0.0/8` β€” IPv4 loopback
263+
*`::1/128` β€” IPv6 loopback
264+
*`169.254.0.0/16` β€” IPv4 link-local
265+
*`fe80::/10` β€” IPv6 link-local
266+
*`fc00::/7` β€” IPv6 unique local (ULA)
267+
268+
```js
269+
constblockList=newnet.BlockList();
270+
blockList.addCIDRs(net.BlockList.PRIVATE_RANGES);
271+
272+
console.log(blockList.check('10.0.0.1')); // Prints: true
273+
console.log(blockList.check('127.0.0.1')); // Prints: true
274+
console.log(blockList.check('8.8.8.8')); // Prints: false
275+
```
276+
277+
### `blockList.removeAddress(address[, type])`
278+
279+
<!-- YAML
280+
added: REPLACEME
281+
-->
282+
283+
*`address` {string|net.SocketAddress} An IPv4 or IPv6 address.
284+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
285+
286+
Removes a rule that was previously added with `blockList.addAddress()`. The
287+
address must match exactly the value used when the rule was added. If the
288+
specified address does not exist, this is a no-op.
289+
290+
### `blockList.removeCIDR(cidr)`
291+
292+
<!-- YAML
293+
added: REPLACEME
294+
-->
295+
296+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
297+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
298+
299+
Removes a subnet rule using CIDR notation. The address family is automatically
300+
detected from the address. This is equivalent to calling
301+
`blockList.removeSubnet()` with the parsed network address, prefix length,
302+
and family. If the specified subnet does not exist, this is a no-op.
303+
304+
### `blockList.removeRange(start, end[, type])`
305+
306+
<!-- YAML
307+
added: REPLACEME
308+
-->
309+
310+
*`start` {string|net.SocketAddress} The starting IPv4 or IPv6 address in the
311+
range.
312+
*`end` {string|net.SocketAddress} The ending IPv4 or IPv6 address in the range.
313+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
314+
315+
Removes a rule that was previously added with `blockList.addRange()`. The `start`
316+
and `end` addresses must match exactly the values used when the rule was added.
317+
If the specified range does not exist, this is a no-op.
318+
319+
### `blockList.removeSubnet(net, prefix[, type])`
320+
321+
<!-- YAML
322+
added: REPLACEME
323+
-->
324+
325+
*`net` {string|net.SocketAddress} The network IPv4 or IPv6 address.
326+
*`prefix` {number} The number of CIDR prefix bits. For IPv4, this
327+
must be a value between `0` and `32`. For IPv6, this must be between
328+
`0` and `128`.
329+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
330+
331+
Removes a rule that was previously added with `blockList.addSubnet()`. The
332+
network address and prefix must match exactly the values used when the rule was
333+
added. If the specified subnet does not exist, this is a no-op.
334+
335+
### `blockList.rules`
336+
337+
<!-- YAML
338+
added:
339+
- v15.0.0
340+
- v14.18.0
341+
-->
342+
343+
* Type: {string\[]}
344+
345+
The list of rules added to the blocklist.
346+
347+
### `blockList.size`
348+
349+
<!-- YAML
350+
added: REPLACEME
351+
-->
352+
353+
* Type: {number}
354+
355+
The number of rules in the blocklist. This is equivalent to
356+
`blockList.rules.length` but does not allocate the rules array.
357+
208358
### `blockList.toJSON()`
209359

210360
> Stability: 1.2 - Release candidate

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 3d7d277

Browse files
jasnelladuh95
authored andcommitted
net: improve performance of net.BlockList
* fix duplicate address insertion in SocketAddressBlockList * fix BlockList rule listing order to match apply * add minor bound check in BlockList * improve performance of BlockList apply * eliminating shared_ptr * check fast api path * add clear method to BlockList * general storage improvements to BlockList * use shared locks for BlockList reads * add bulk address adding to BlockList * add BlockList benchmark * add remove range/subnet to BlockList * add cidr notation parsing to BlockList * add additional apis to BlockList * add private subnet presets to BlockList Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: OpenCode/Opus PR-URL: #64974 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
1 parent e9327d1 commit 3d7d277

8 files changed

Lines changed: 2061 additions & 127 deletions

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
'use strict';
2+
3+
constcommon=require('../common.js');
4+
const{ BlockList, SocketAddress }=require('net');
5+
6+
consthasAddAddresses=typeofBlockList.prototype.addAddresses==='function';
7+
8+
constoperations=['check','checkWithSocketAddress','addAddress'];
9+
if(hasAddAddresses){
10+
operations.push('addAddresses');
11+
}
12+
13+
constbench=common.createBenchmark(main,{
14+
n: [1e6],
15+
ruleCount: [10,100,1000,10000],
16+
ruleType: ['address','subnet','mixed'],
17+
checkResult: ['hit','miss'],
18+
operation: operations,
19+
},{
20+
combinationFilter({ operation, ruleCount, ruleType }){
21+
// addAddress and addAddresses only need address rules, not subnets.
22+
if((operation==='addAddress'||operation==='addAddresses')&&
23+
ruleType!=='address'){
24+
returnfalse;
25+
}
26+
returntrue;
27+
},
28+
});
29+
30+
functiongenerateIPv4(index){
31+
return`${(index>>>24)&0xff}.${(index>>>16)&0xff}.`+
32+
`${(index>>>8)&0xff}.${index&0xff}`;
33+
}
34+
35+
functionbuildBlockList(ruleCount,ruleType){
36+
constblockList=newBlockList();
37+
38+
if(ruleType==='address'||ruleType==='mixed'){
39+
constaddressCount=ruleType==='mixed' ?
40+
Math.floor(ruleCount/2) : ruleCount;
41+
constaddresses=[];
42+
for(leti=0;i<addressCount;i++){
43+
// Start from 10.0.0.1 to avoid 0.0.0.0
44+
addresses.push(generateIPv4(0x0a000001+i));
45+
}
46+
if(hasAddAddresses){
47+
blockList.addAddresses(addresses);
48+
}else{
49+
for(constaddrofaddresses){
50+
blockList.addAddress(addr);
51+
}
52+
}
53+
}
54+
55+
if(ruleType==='subnet'||ruleType==='mixed'){
56+
constsubnetCount=ruleType==='mixed' ?
57+
Math.floor(ruleCount/2) : ruleCount;
58+
for(leti=0;i<subnetCount;i++){
59+
// Use distinct /24 subnets: 172.i.j.0/24
60+
constsecond=(i>>>8)&0xff;
61+
constthird=i&0xff;
62+
blockList.addSubnet(`172.${second}.${third}.0`,24);
63+
}
64+
}
65+
66+
returnblockList;
67+
}
68+
69+
functionmain({ n, ruleCount, ruleType, checkResult, operation }){
70+
if(operation==='check'){
71+
benchCheck(n,ruleCount,ruleType,checkResult);
72+
}elseif(operation==='checkWithSocketAddress'){
73+
benchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult);
74+
}elseif(operation==='addAddress'){
75+
benchAddAddress(n,ruleCount);
76+
}elseif(operation==='addAddresses'){
77+
benchAddAddresses(n,ruleCount);
78+
}
79+
}
80+
81+
// Benchmark check() with string addresses (the common JS API path).
82+
functionbenchCheck(n,ruleCount,ruleType,checkResult){
83+
constblockList=buildBlockList(ruleCount,ruleType);
84+
85+
// For 'hit', use an address that's in the list.
86+
// For 'miss', use an address that's not in the list.
87+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
88+
89+
bench.start();
90+
for(leti=0;i<n;i++){
91+
blockList.check(address);
92+
}
93+
bench.end(n);
94+
}
95+
96+
// Benchmark check() with pre-created SocketAddress objects
97+
// (avoids measuring SocketAddress construction overhead).
98+
functionbenchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult){
99+
constblockList=buildBlockList(ruleCount,ruleType);
100+
101+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
102+
constsa=newSocketAddress({ address });
103+
104+
bench.start();
105+
for(leti=0;i<n;i++){
106+
blockList.check(sa);
107+
}
108+
bench.end(n);
109+
}
110+
111+
// Benchmark single addAddress() calls (one lock acquire per call).
112+
functionbenchAddAddress(n,ruleCount){
113+
// Scale n down for large rule counts to keep runtime reasonable.
114+
constiterations=Math.min(n,ruleCount*100);
115+
116+
constaddresses=[];
117+
for(leti=0;i<ruleCount;i++){
118+
addresses.push(generateIPv4(0x0a000001+i));
119+
}
120+
121+
bench.start();
122+
for(leti=0;i<iterations;i++){
123+
constblockList=newBlockList();
124+
for(letj=0;j<addresses.length;j++){
125+
blockList.addAddress(addresses[j]);
126+
}
127+
}
128+
bench.end(iterations);
129+
}
130+
131+
// Benchmark batch addAddresses() (one lock acquire per batch).
132+
functionbenchAddAddresses(n,ruleCount){
133+
constiterations=Math.min(n,ruleCount*100);
134+
135+
constaddresses=[];
136+
for(leti=0;i<ruleCount;i++){
137+
addresses.push(generateIPv4(0x0a000001+i));
138+
}
139+
140+
bench.start();
141+
for(leti=0;i<iterations;i++){
142+
constblockList=newBlockList();
143+
blockList.addAddresses(addresses);
144+
}
145+
bench.end(iterations);
146+
}

β€Ždoc/api/net.mdβ€Ž

Lines changed: 169 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,47 @@ added:
9696

9797
Adds a rule to block the given IP address.
9898

99+
### `blockList.addAddresses(addresses[, type])`
100+
101+
<!-- YAML
102+
added: REPLACEME
103+
-->
104+
105+
*`addresses` {string\[]|net.SocketAddress\[]} An array of IPv4 or IPv6
106+
addresses.
107+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
108+
109+
Adds multiple address rules to the block list in a single operation.
110+
This is more efficient than calling `blockList.addAddress()` repeatedly
111+
when adding a large number of individual addresses, as the addresses
112+
are inserted under a single internal lock acquisition.
113+
114+
### `blockList.addCIDR(cidr)`
115+
116+
<!-- YAML
117+
added: REPLACEME
118+
-->
119+
120+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
121+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
122+
123+
Adds a subnet rule using CIDR notation. The address family is automatically
124+
detected from the address (IPv6 if the address contains `':'`, IPv4
125+
otherwise). This is equivalent to calling `blockList.addSubnet()` with
126+
the parsed network address, prefix length, and family.
127+
128+
### `blockList.addCIDRs(cidrs)`
129+
130+
<!-- YAML
131+
added: REPLACEME
132+
-->
133+
134+
*`cidrs` {string\[]} An array of IPv4 or IPv6 subnets in CIDR notation.
135+
136+
Adds multiple subnet rules using CIDR notation in a single call. The address
137+
family for each entry is automatically detected. This is equivalent to
138+
calling `blockList.addCIDR()` for each element of the array.
139+
99140
### `blockList.addRange(start, end[, type])`
100141

101142
<!-- YAML
@@ -158,28 +199,13 @@ console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
158199
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
159200
```
160201

161-
### `blockList.rules`
202+
### `blockList.clear()`
162203

163-
<!-- YAML
164-
added:
165-
- v15.0.0
166-
- v14.18.0
204+
<!--
205+
added: REPLACEME
167206
-->
168207

169-
* Type: {string\[]}
170-
171-
The list of rules added to the blocklist.
172-
173-
### `BlockList.isBlockList(value)`
174-
175-
<!-- YAML
176-
added:
177-
- v23.4.0
178-
- v22.13.0
179-
-->
180-
181-
*`value` {any} Any JS value
182-
* Returns `true` if the `value` is a `net.BlockList`.
208+
Clears all rules from the `BlockList`.
183209

184210
### `blockList.fromJSON(value)`
185211

@@ -205,6 +231,130 @@ blockList.fromJSON(JSON.stringify(data));
205231

206232
*`value` Blocklist.rules
207233

234+
### `BlockList.isBlockList(value)`
235+
236+
<!-- YAML
237+
added:
238+
- v23.4.0
239+
- v22.13.0
240+
-->
241+
242+
*`value` {any} Any JS value
243+
* Returns `true` if the `value` is a `net.BlockList`.
244+
245+
### `BlockList.PRIVATE_RANGES`
246+
247+
<!-- YAML
248+
added: REPLACEME
249+
-->
250+
251+
* Type: {string\[]}
252+
253+
A frozen array of CIDR strings representing private, loopback, and link-local
254+
IP address ranges. This can be passed to `blockList.addCIDRs()` to quickly
255+
populate a blocklist with all non-routable address ranges.
256+
257+
The included ranges are:
258+
259+
*`10.0.0.0/8` β€” RFC 1918 private IPv4
260+
*`172.16.0.0/12` β€” RFC 1918 private IPv4
261+
*`192.168.0.0/16` β€” RFC 1918 private IPv4
262+
*`127.0.0.0/8` β€” IPv4 loopback
263+
*`::1/128` β€” IPv6 loopback
264+
*`169.254.0.0/16` β€” IPv4 link-local
265+
*`fe80::/10` β€” IPv6 link-local
266+
*`fc00::/7` β€” IPv6 unique local (ULA)
267+
268+
```js
269+
constblockList=newnet.BlockList();
270+
blockList.addCIDRs(net.BlockList.PRIVATE_RANGES);
271+
272+
console.log(blockList.check('10.0.0.1')); // Prints: true
273+
console.log(blockList.check('127.0.0.1')); // Prints: true
274+
console.log(blockList.check('8.8.8.8')); // Prints: false
275+
```
276+
277+
### `blockList.removeAddress(address[, type])`
278+
279+
<!-- YAML
280+
added: REPLACEME
281+
-->
282+
283+
*`address` {string|net.SocketAddress} An IPv4 or IPv6 address.
284+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
285+
286+
Removes a rule that was previously added with `blockList.addAddress()`. The
287+
address must match exactly the value used when the rule was added. If the
288+
specified address does not exist, this is a no-op.
289+
290+
### `blockList.removeCIDR(cidr)`
291+
292+
<!-- YAML
293+
added: REPLACEME
294+
-->
295+
296+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
297+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
298+
299+
Removes a subnet rule using CIDR notation. The address family is automatically
300+
detected from the address. This is equivalent to calling
301+
`blockList.removeSubnet()` with the parsed network address, prefix length,
302+
and family. If the specified subnet does not exist, this is a no-op.
303+
304+
### `blockList.removeRange(start, end[, type])`
305+
306+
<!-- YAML
307+
added: REPLACEME
308+
-->
309+
310+
*`start` {string|net.SocketAddress} The starting IPv4 or IPv6 address in the
311+
range.
312+
*`end` {string|net.SocketAddress} The ending IPv4 or IPv6 address in the range.
313+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
314+
315+
Removes a rule that was previously added with `blockList.addRange()`. The `start`
316+
and `end` addresses must match exactly the values used when the rule was added.
317+
If the specified range does not exist, this is a no-op.
318+
319+
### `blockList.removeSubnet(net, prefix[, type])`
320+
321+
<!-- YAML
322+
added: REPLACEME
323+
-->
324+
325+
*`net` {string|net.SocketAddress} The network IPv4 or IPv6 address.
326+
*`prefix` {number} The number of CIDR prefix bits. For IPv4, this
327+
must be a value between `0` and `32`. For IPv6, this must be between
328+
`0` and `128`.
329+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
330+
331+
Removes a rule that was previously added with `blockList.addSubnet()`. The
332+
network address and prefix must match exactly the values used when the rule was
333+
added. If the specified subnet does not exist, this is a no-op.
334+
335+
### `blockList.rules`
336+
337+
<!-- YAML
338+
added:
339+
- v15.0.0
340+
- v14.18.0
341+
-->
342+
343+
* Type: {string\[]}
344+
345+
The list of rules added to the blocklist.
346+
347+
### `blockList.size`
348+
349+
<!-- YAML
350+
added: REPLACEME
351+
-->
352+
353+
* Type: {number}
354+
355+
The number of rules in the blocklist. This is equivalent to
356+
`blockList.rules.length` but does not allocate the rules array.
357+
208358
### `blockList.toJSON()`
209359

210360
> Stability: 1.2 - Release candidate

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Commit 3d7d277

Browse files
jasnelladuh95
authored andcommitted
net: improve performance of net.BlockList
* fix duplicate address insertion in SocketAddressBlockList * fix BlockList rule listing order to match apply * add minor bound check in BlockList * improve performance of BlockList apply * eliminating shared_ptr * check fast api path * add clear method to BlockList * general storage improvements to BlockList * use shared locks for BlockList reads * add bulk address adding to BlockList * add BlockList benchmark * add remove range/subnet to BlockList * add cidr notation parsing to BlockList * add additional apis to BlockList * add private subnet presets to BlockList Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: OpenCode/Opus PR-URL: #64974 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
1 parent e9327d1 commit 3d7d277

8 files changed

Lines changed: 2061 additions & 127 deletions

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
'use strict';
2+
3+
constcommon=require('../common.js');
4+
const{ BlockList, SocketAddress }=require('net');
5+
6+
consthasAddAddresses=typeofBlockList.prototype.addAddresses==='function';
7+
8+
constoperations=['check','checkWithSocketAddress','addAddress'];
9+
if(hasAddAddresses){
10+
operations.push('addAddresses');
11+
}
12+
13+
constbench=common.createBenchmark(main,{
14+
n: [1e6],
15+
ruleCount: [10,100,1000,10000],
16+
ruleType: ['address','subnet','mixed'],
17+
checkResult: ['hit','miss'],
18+
operation: operations,
19+
},{
20+
combinationFilter({ operation, ruleCount, ruleType }){
21+
// addAddress and addAddresses only need address rules, not subnets.
22+
if((operation==='addAddress'||operation==='addAddresses')&&
23+
ruleType!=='address'){
24+
returnfalse;
25+
}
26+
returntrue;
27+
},
28+
});
29+
30+
functiongenerateIPv4(index){
31+
return`${(index>>>24)&0xff}.${(index>>>16)&0xff}.`+
32+
`${(index>>>8)&0xff}.${index&0xff}`;
33+
}
34+
35+
functionbuildBlockList(ruleCount,ruleType){
36+
constblockList=newBlockList();
37+
38+
if(ruleType==='address'||ruleType==='mixed'){
39+
constaddressCount=ruleType==='mixed' ?
40+
Math.floor(ruleCount/2) : ruleCount;
41+
constaddresses=[];
42+
for(leti=0;i<addressCount;i++){
43+
// Start from 10.0.0.1 to avoid 0.0.0.0
44+
addresses.push(generateIPv4(0x0a000001+i));
45+
}
46+
if(hasAddAddresses){
47+
blockList.addAddresses(addresses);
48+
}else{
49+
for(constaddrofaddresses){
50+
blockList.addAddress(addr);
51+
}
52+
}
53+
}
54+
55+
if(ruleType==='subnet'||ruleType==='mixed'){
56+
constsubnetCount=ruleType==='mixed' ?
57+
Math.floor(ruleCount/2) : ruleCount;
58+
for(leti=0;i<subnetCount;i++){
59+
// Use distinct /24 subnets: 172.i.j.0/24
60+
constsecond=(i>>>8)&0xff;
61+
constthird=i&0xff;
62+
blockList.addSubnet(`172.${second}.${third}.0`,24);
63+
}
64+
}
65+
66+
returnblockList;
67+
}
68+
69+
functionmain({ n, ruleCount, ruleType, checkResult, operation }){
70+
if(operation==='check'){
71+
benchCheck(n,ruleCount,ruleType,checkResult);
72+
}elseif(operation==='checkWithSocketAddress'){
73+
benchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult);
74+
}elseif(operation==='addAddress'){
75+
benchAddAddress(n,ruleCount);
76+
}elseif(operation==='addAddresses'){
77+
benchAddAddresses(n,ruleCount);
78+
}
79+
}
80+
81+
// Benchmark check() with string addresses (the common JS API path).
82+
functionbenchCheck(n,ruleCount,ruleType,checkResult){
83+
constblockList=buildBlockList(ruleCount,ruleType);
84+
85+
// For 'hit', use an address that's in the list.
86+
// For 'miss', use an address that's not in the list.
87+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
88+
89+
bench.start();
90+
for(leti=0;i<n;i++){
91+
blockList.check(address);
92+
}
93+
bench.end(n);
94+
}
95+
96+
// Benchmark check() with pre-created SocketAddress objects
97+
// (avoids measuring SocketAddress construction overhead).
98+
functionbenchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult){
99+
constblockList=buildBlockList(ruleCount,ruleType);
100+
101+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
102+
constsa=newSocketAddress({ address });
103+
104+
bench.start();
105+
for(leti=0;i<n;i++){
106+
blockList.check(sa);
107+
}
108+
bench.end(n);
109+
}
110+
111+
// Benchmark single addAddress() calls (one lock acquire per call).
112+
functionbenchAddAddress(n,ruleCount){
113+
// Scale n down for large rule counts to keep runtime reasonable.
114+
constiterations=Math.min(n,ruleCount*100);
115+
116+
constaddresses=[];
117+
for(leti=0;i<ruleCount;i++){
118+
addresses.push(generateIPv4(0x0a000001+i));
119+
}
120+
121+
bench.start();
122+
for(leti=0;i<iterations;i++){
123+
constblockList=newBlockList();
124+
for(letj=0;j<addresses.length;j++){
125+
blockList.addAddress(addresses[j]);
126+
}
127+
}
128+
bench.end(iterations);
129+
}
130+
131+
// Benchmark batch addAddresses() (one lock acquire per batch).
132+
functionbenchAddAddresses(n,ruleCount){
133+
constiterations=Math.min(n,ruleCount*100);
134+
135+
constaddresses=[];
136+
for(leti=0;i<ruleCount;i++){
137+
addresses.push(generateIPv4(0x0a000001+i));
138+
}
139+
140+
bench.start();
141+
for(leti=0;i<iterations;i++){
142+
constblockList=newBlockList();
143+
blockList.addAddresses(addresses);
144+
}
145+
bench.end(iterations);
146+
}

β€Ždoc/api/net.mdβ€Ž

Lines changed: 169 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,47 @@ added:
9696

9797
Adds a rule to block the given IP address.
9898

99+
### `blockList.addAddresses(addresses[, type])`
100+
101+
<!-- YAML
102+
added: REPLACEME
103+
-->
104+
105+
*`addresses` {string\[]|net.SocketAddress\[]} An array of IPv4 or IPv6
106+
addresses.
107+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
108+
109+
Adds multiple address rules to the block list in a single operation.
110+
This is more efficient than calling `blockList.addAddress()` repeatedly
111+
when adding a large number of individual addresses, as the addresses
112+
are inserted under a single internal lock acquisition.
113+
114+
### `blockList.addCIDR(cidr)`
115+
116+
<!-- YAML
117+
added: REPLACEME
118+
-->
119+
120+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
121+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
122+
123+
Adds a subnet rule using CIDR notation. The address family is automatically
124+
detected from the address (IPv6 if the address contains `':'`, IPv4
125+
otherwise). This is equivalent to calling `blockList.addSubnet()` with
126+
the parsed network address, prefix length, and family.
127+
128+
### `blockList.addCIDRs(cidrs)`
129+
130+
<!-- YAML
131+
added: REPLACEME
132+
-->
133+
134+
*`cidrs` {string\[]} An array of IPv4 or IPv6 subnets in CIDR notation.
135+
136+
Adds multiple subnet rules using CIDR notation in a single call. The address
137+
family for each entry is automatically detected. This is equivalent to
138+
calling `blockList.addCIDR()` for each element of the array.
139+
99140
### `blockList.addRange(start, end[, type])`
100141

101142
<!-- YAML
@@ -158,28 +199,13 @@ console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
158199
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
159200
```
160201

161-
### `blockList.rules`
202+
### `blockList.clear()`
162203

163-
<!-- YAML
164-
added:
165-
- v15.0.0
166-
- v14.18.0
204+
<!--
205+
added: REPLACEME
167206
-->
168207

169-
* Type: {string\[]}
170-
171-
The list of rules added to the blocklist.
172-
173-
### `BlockList.isBlockList(value)`
174-
175-
<!-- YAML
176-
added:
177-
- v23.4.0
178-
- v22.13.0
179-
-->
180-
181-
*`value` {any} Any JS value
182-
* Returns `true` if the `value` is a `net.BlockList`.
208+
Clears all rules from the `BlockList`.
183209

184210
### `blockList.fromJSON(value)`
185211

@@ -205,6 +231,130 @@ blockList.fromJSON(JSON.stringify(data));
205231

206232
*`value` Blocklist.rules
207233

234+
### `BlockList.isBlockList(value)`
235+
236+
<!-- YAML
237+
added:
238+
- v23.4.0
239+
- v22.13.0
240+
-->
241+
242+
*`value` {any} Any JS value
243+
* Returns `true` if the `value` is a `net.BlockList`.
244+
245+
### `BlockList.PRIVATE_RANGES`
246+
247+
<!-- YAML
248+
added: REPLACEME
249+
-->
250+
251+
* Type: {string\[]}
252+
253+
A frozen array of CIDR strings representing private, loopback, and link-local
254+
IP address ranges. This can be passed to `blockList.addCIDRs()` to quickly
255+
populate a blocklist with all non-routable address ranges.
256+
257+
The included ranges are:
258+
259+
*`10.0.0.0/8` β€” RFC 1918 private IPv4
260+
*`172.16.0.0/12` β€” RFC 1918 private IPv4
261+
*`192.168.0.0/16` β€” RFC 1918 private IPv4
262+
*`127.0.0.0/8` β€” IPv4 loopback
263+
*`::1/128` β€” IPv6 loopback
264+
*`169.254.0.0/16` β€” IPv4 link-local
265+
*`fe80::/10` β€” IPv6 link-local
266+
*`fc00::/7` β€” IPv6 unique local (ULA)
267+
268+
```js
269+
constblockList=newnet.BlockList();
270+
blockList.addCIDRs(net.BlockList.PRIVATE_RANGES);
271+
272+
console.log(blockList.check('10.0.0.1')); // Prints: true
273+
console.log(blockList.check('127.0.0.1')); // Prints: true
274+
console.log(blockList.check('8.8.8.8')); // Prints: false
275+
```
276+
277+
### `blockList.removeAddress(address[, type])`
278+
279+
<!-- YAML
280+
added: REPLACEME
281+
-->
282+
283+
*`address` {string|net.SocketAddress} An IPv4 or IPv6 address.
284+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
285+
286+
Removes a rule that was previously added with `blockList.addAddress()`. The
287+
address must match exactly the value used when the rule was added. If the
288+
specified address does not exist, this is a no-op.
289+
290+
### `blockList.removeCIDR(cidr)`
291+
292+
<!-- YAML
293+
added: REPLACEME
294+
-->
295+
296+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
297+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
298+
299+
Removes a subnet rule using CIDR notation. The address family is automatically
300+
detected from the address. This is equivalent to calling
301+
`blockList.removeSubnet()` with the parsed network address, prefix length,
302+
and family. If the specified subnet does not exist, this is a no-op.
303+
304+
### `blockList.removeRange(start, end[, type])`
305+
306+
<!-- YAML
307+
added: REPLACEME
308+
-->
309+
310+
*`start` {string|net.SocketAddress} The starting IPv4 or IPv6 address in the
311+
range.
312+
*`end` {string|net.SocketAddress} The ending IPv4 or IPv6 address in the range.
313+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
314+
315+
Removes a rule that was previously added with `blockList.addRange()`. The `start`
316+
and `end` addresses must match exactly the values used when the rule was added.
317+
If the specified range does not exist, this is a no-op.
318+
319+
### `blockList.removeSubnet(net, prefix[, type])`
320+
321+
<!-- YAML
322+
added: REPLACEME
323+
-->
324+
325+
*`net` {string|net.SocketAddress} The network IPv4 or IPv6 address.
326+
*`prefix` {number} The number of CIDR prefix bits. For IPv4, this
327+
must be a value between `0` and `32`. For IPv6, this must be between
328+
`0` and `128`.
329+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
330+
331+
Removes a rule that was previously added with `blockList.addSubnet()`. The
332+
network address and prefix must match exactly the values used when the rule was
333+
added. If the specified subnet does not exist, this is a no-op.
334+
335+
### `blockList.rules`
336+
337+
<!-- YAML
338+
added:
339+
- v15.0.0
340+
- v14.18.0
341+
-->
342+
343+
* Type: {string\[]}
344+
345+
The list of rules added to the blocklist.
346+
347+
### `blockList.size`
348+
349+
<!-- YAML
350+
added: REPLACEME
351+
-->
352+
353+
* Type: {number}
354+
355+
The number of rules in the blocklist. This is equivalent to
356+
`blockList.rules.length` but does not allocate the rules array.
357+
208358
### `blockList.toJSON()`
209359

210360
> Stability: 1.2 - Release candidate

0 commit comments

Comments
Β (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Commit 3d7d277

Browse files
jasnelladuh95
authored andcommitted
net: improve performance of net.BlockList
* fix duplicate address insertion in SocketAddressBlockList * fix BlockList rule listing order to match apply * add minor bound check in BlockList * improve performance of BlockList apply * eliminating shared_ptr * check fast api path * add clear method to BlockList * general storage improvements to BlockList * use shared locks for BlockList reads * add bulk address adding to BlockList * add BlockList benchmark * add remove range/subnet to BlockList * add cidr notation parsing to BlockList * add additional apis to BlockList * add private subnet presets to BlockList Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: OpenCode/Opus PR-URL: #64974 Reviewed-By: Tim Perry <pimterry@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
1 parent e9327d1 commit 3d7d277

8 files changed

Lines changed: 2061 additions & 127 deletions

File tree

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
'use strict';
2+
3+
constcommon=require('../common.js');
4+
const{ BlockList, SocketAddress }=require('net');
5+
6+
consthasAddAddresses=typeofBlockList.prototype.addAddresses==='function';
7+
8+
constoperations=['check','checkWithSocketAddress','addAddress'];
9+
if(hasAddAddresses){
10+
operations.push('addAddresses');
11+
}
12+
13+
constbench=common.createBenchmark(main,{
14+
n: [1e6],
15+
ruleCount: [10,100,1000,10000],
16+
ruleType: ['address','subnet','mixed'],
17+
checkResult: ['hit','miss'],
18+
operation: operations,
19+
},{
20+
combinationFilter({ operation, ruleCount, ruleType }){
21+
// addAddress and addAddresses only need address rules, not subnets.
22+
if((operation==='addAddress'||operation==='addAddresses')&&
23+
ruleType!=='address'){
24+
returnfalse;
25+
}
26+
returntrue;
27+
},
28+
});
29+
30+
functiongenerateIPv4(index){
31+
return`${(index>>>24)&0xff}.${(index>>>16)&0xff}.`+
32+
`${(index>>>8)&0xff}.${index&0xff}`;
33+
}
34+
35+
functionbuildBlockList(ruleCount,ruleType){
36+
constblockList=newBlockList();
37+
38+
if(ruleType==='address'||ruleType==='mixed'){
39+
constaddressCount=ruleType==='mixed' ?
40+
Math.floor(ruleCount/2) : ruleCount;
41+
constaddresses=[];
42+
for(leti=0;i<addressCount;i++){
43+
// Start from 10.0.0.1 to avoid 0.0.0.0
44+
addresses.push(generateIPv4(0x0a000001+i));
45+
}
46+
if(hasAddAddresses){
47+
blockList.addAddresses(addresses);
48+
}else{
49+
for(constaddrofaddresses){
50+
blockList.addAddress(addr);
51+
}
52+
}
53+
}
54+
55+
if(ruleType==='subnet'||ruleType==='mixed'){
56+
constsubnetCount=ruleType==='mixed' ?
57+
Math.floor(ruleCount/2) : ruleCount;
58+
for(leti=0;i<subnetCount;i++){
59+
// Use distinct /24 subnets: 172.i.j.0/24
60+
constsecond=(i>>>8)&0xff;
61+
constthird=i&0xff;
62+
blockList.addSubnet(`172.${second}.${third}.0`,24);
63+
}
64+
}
65+
66+
returnblockList;
67+
}
68+
69+
functionmain({ n, ruleCount, ruleType, checkResult, operation }){
70+
if(operation==='check'){
71+
benchCheck(n,ruleCount,ruleType,checkResult);
72+
}elseif(operation==='checkWithSocketAddress'){
73+
benchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult);
74+
}elseif(operation==='addAddress'){
75+
benchAddAddress(n,ruleCount);
76+
}elseif(operation==='addAddresses'){
77+
benchAddAddresses(n,ruleCount);
78+
}
79+
}
80+
81+
// Benchmark check() with string addresses (the common JS API path).
82+
functionbenchCheck(n,ruleCount,ruleType,checkResult){
83+
constblockList=buildBlockList(ruleCount,ruleType);
84+
85+
// For 'hit', use an address that's in the list.
86+
// For 'miss', use an address that's not in the list.
87+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
88+
89+
bench.start();
90+
for(leti=0;i<n;i++){
91+
blockList.check(address);
92+
}
93+
bench.end(n);
94+
}
95+
96+
// Benchmark check() with pre-created SocketAddress objects
97+
// (avoids measuring SocketAddress construction overhead).
98+
functionbenchCheckWithSocketAddress(n,ruleCount,ruleType,checkResult){
99+
constblockList=buildBlockList(ruleCount,ruleType);
100+
101+
constaddress=checkResult==='hit' ? '10.0.0.1' : '192.168.255.255';
102+
constsa=newSocketAddress({ address });
103+
104+
bench.start();
105+
for(leti=0;i<n;i++){
106+
blockList.check(sa);
107+
}
108+
bench.end(n);
109+
}
110+
111+
// Benchmark single addAddress() calls (one lock acquire per call).
112+
functionbenchAddAddress(n,ruleCount){
113+
// Scale n down for large rule counts to keep runtime reasonable.
114+
constiterations=Math.min(n,ruleCount*100);
115+
116+
constaddresses=[];
117+
for(leti=0;i<ruleCount;i++){
118+
addresses.push(generateIPv4(0x0a000001+i));
119+
}
120+
121+
bench.start();
122+
for(leti=0;i<iterations;i++){
123+
constblockList=newBlockList();
124+
for(letj=0;j<addresses.length;j++){
125+
blockList.addAddress(addresses[j]);
126+
}
127+
}
128+
bench.end(iterations);
129+
}
130+
131+
// Benchmark batch addAddresses() (one lock acquire per batch).
132+
functionbenchAddAddresses(n,ruleCount){
133+
constiterations=Math.min(n,ruleCount*100);
134+
135+
constaddresses=[];
136+
for(leti=0;i<ruleCount;i++){
137+
addresses.push(generateIPv4(0x0a000001+i));
138+
}
139+
140+
bench.start();
141+
for(leti=0;i<iterations;i++){
142+
constblockList=newBlockList();
143+
blockList.addAddresses(addresses);
144+
}
145+
bench.end(iterations);
146+
}

β€Ždoc/api/net.mdβ€Ž

Lines changed: 169 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,47 @@ added:
9696

9797
Adds a rule to block the given IP address.
9898

99+
### `blockList.addAddresses(addresses[, type])`
100+
101+
<!-- YAML
102+
added: REPLACEME
103+
-->
104+
105+
*`addresses` {string\[]|net.SocketAddress\[]} An array of IPv4 or IPv6
106+
addresses.
107+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
108+
109+
Adds multiple address rules to the block list in a single operation.
110+
This is more efficient than calling `blockList.addAddress()` repeatedly
111+
when adding a large number of individual addresses, as the addresses
112+
are inserted under a single internal lock acquisition.
113+
114+
### `blockList.addCIDR(cidr)`
115+
116+
<!-- YAML
117+
added: REPLACEME
118+
-->
119+
120+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
121+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
122+
123+
Adds a subnet rule using CIDR notation. The address family is automatically
124+
detected from the address (IPv6 if the address contains `':'`, IPv4
125+
otherwise). This is equivalent to calling `blockList.addSubnet()` with
126+
the parsed network address, prefix length, and family.
127+
128+
### `blockList.addCIDRs(cidrs)`
129+
130+
<!-- YAML
131+
added: REPLACEME
132+
-->
133+
134+
*`cidrs` {string\[]} An array of IPv4 or IPv6 subnets in CIDR notation.
135+
136+
Adds multiple subnet rules using CIDR notation in a single call. The address
137+
family for each entry is automatically detected. This is equivalent to
138+
calling `blockList.addCIDR()` for each element of the array.
139+
99140
### `blockList.addRange(start, end[, type])`
100141

101142
<!-- YAML
@@ -158,28 +199,13 @@ console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
158199
console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
159200
```
160201

161-
### `blockList.rules`
202+
### `blockList.clear()`
162203

163-
<!-- YAML
164-
added:
165-
- v15.0.0
166-
- v14.18.0
204+
<!--
205+
added: REPLACEME
167206
-->
168207

169-
* Type: {string\[]}
170-
171-
The list of rules added to the blocklist.
172-
173-
### `BlockList.isBlockList(value)`
174-
175-
<!-- YAML
176-
added:
177-
- v23.4.0
178-
- v22.13.0
179-
-->
180-
181-
*`value` {any} Any JS value
182-
* Returns `true` if the `value` is a `net.BlockList`.
208+
Clears all rules from the `BlockList`.
183209

184210
### `blockList.fromJSON(value)`
185211

@@ -205,6 +231,130 @@ blockList.fromJSON(JSON.stringify(data));
205231

206232
*`value` Blocklist.rules
207233

234+
### `BlockList.isBlockList(value)`
235+
236+
<!-- YAML
237+
added:
238+
- v23.4.0
239+
- v22.13.0
240+
-->
241+
242+
*`value` {any} Any JS value
243+
* Returns `true` if the `value` is a `net.BlockList`.
244+
245+
### `BlockList.PRIVATE_RANGES`
246+
247+
<!-- YAML
248+
added: REPLACEME
249+
-->
250+
251+
* Type: {string\[]}
252+
253+
A frozen array of CIDR strings representing private, loopback, and link-local
254+
IP address ranges. This can be passed to `blockList.addCIDRs()` to quickly
255+
populate a blocklist with all non-routable address ranges.
256+
257+
The included ranges are:
258+
259+
*`10.0.0.0/8` β€” RFC 1918 private IPv4
260+
*`172.16.0.0/12` β€” RFC 1918 private IPv4
261+
*`192.168.0.0/16` β€” RFC 1918 private IPv4
262+
*`127.0.0.0/8` β€” IPv4 loopback
263+
*`::1/128` β€” IPv6 loopback
264+
*`169.254.0.0/16` β€” IPv4 link-local
265+
*`fe80::/10` β€” IPv6 link-local
266+
*`fc00::/7` β€” IPv6 unique local (ULA)
267+
268+
```js
269+
constblockList=newnet.BlockList();
270+
blockList.addCIDRs(net.BlockList.PRIVATE_RANGES);
271+
272+
console.log(blockList.check('10.0.0.1')); // Prints: true
273+
console.log(blockList.check('127.0.0.1')); // Prints: true
274+
console.log(blockList.check('8.8.8.8')); // Prints: false
275+
```
276+
277+
### `blockList.removeAddress(address[, type])`
278+
279+
<!-- YAML
280+
added: REPLACEME
281+
-->
282+
283+
*`address` {string|net.SocketAddress} An IPv4 or IPv6 address.
284+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
285+
286+
Removes a rule that was previously added with `blockList.addAddress()`. The
287+
address must match exactly the value used when the rule was added. If the
288+
specified address does not exist, this is a no-op.
289+
290+
### `blockList.removeCIDR(cidr)`
291+
292+
<!-- YAML
293+
added: REPLACEME
294+
-->
295+
296+
*`cidr` {string} An IPv4 or IPv6 subnet in CIDR notation (e.g.
297+
`'10.0.0.0/8'` or `'2001:db8::/32'`).
298+
299+
Removes a subnet rule using CIDR notation. The address family is automatically
300+
detected from the address. This is equivalent to calling
301+
`blockList.removeSubnet()` with the parsed network address, prefix length,
302+
and family. If the specified subnet does not exist, this is a no-op.
303+
304+
### `blockList.removeRange(start, end[, type])`
305+
306+
<!-- YAML
307+
added: REPLACEME
308+
-->
309+
310+
*`start` {string|net.SocketAddress} The starting IPv4 or IPv6 address in the
311+
range.
312+
*`end` {string|net.SocketAddress} The ending IPv4 or IPv6 address in the range.
313+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
314+
315+
Removes a rule that was previously added with `blockList.addRange()`. The `start`
316+
and `end` addresses must match exactly the values used when the rule was added.
317+
If the specified range does not exist, this is a no-op.
318+
319+
### `blockList.removeSubnet(net, prefix[, type])`
320+
321+
<!-- YAML
322+
added: REPLACEME
323+
-->
324+
325+
*`net` {string|net.SocketAddress} The network IPv4 or IPv6 address.
326+
*`prefix` {number} The number of CIDR prefix bits. For IPv4, this
327+
must be a value between `0` and `32`. For IPv6, this must be between
328+
`0` and `128`.
329+
*`type` {string} Either `'ipv4'` or `'ipv6'`. **Default:**`'ipv4'`.
330+
331+
Removes a rule that was previously added with `blockList.addSubnet()`. The
332+
network address and prefix must match exactly the values used when the rule was
333+
added. If the specified subnet does not exist, this is a no-op.
334+
335+
### `blockList.rules`
336+
337+
<!-- YAML
338+
added:
339+
- v15.0.0
340+
- v14.18.0
341+
-->
342+
343+
* Type: {string\[]}
344+
345+
The list of rules added to the blocklist.
346+
347+
### `blockList.size`
348+
349+
<!-- YAML
350+
added: REPLACEME
351+
-->
352+
353+
* Type: {number}
354+
355+
The number of rules in the blocklist. This is equivalent to
356+
`blockList.rules.length` but does not allocate the rules array.
357+
208358
### `blockList.toJSON()`
209359

210360
> Stability: 1.2 - Release candidate

0 commit comments

Comments
Β (0)