From 06ddd62caf797c4626fdc50b88e87a1f0edbd6d8 Mon Sep 17 00:00:00 2001 From: theanarkh Date: Mon, 2 Dec 2024 23:21:31 +0800 Subject: [PATCH] net: support blocklist for net.Server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/56079 Reviewed-By: James M Snell Reviewed-By: Matteo Collina Reviewed-By: Juan José Arboleda --- doc/api/net.md | 5 +++++ lib/net.js | 17 ++++++++++++++++- test/parallel/test-net-server-blocklist.js | 19 +++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-net-server-blocklist.js diff --git a/doc/api/net.md b/doc/api/net.md index 32be5b6bd69ea5..f2d2c20588394c 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -1713,6 +1713,11 @@ changes: **Default:** `false`. * `pauseOnConnect` {boolean} Indicates whether the socket should be paused on incoming connections. **Default:** `false`. + * `blockList` {net.BlockList} `blockList` can be used for disabling inbound + access to specific IP addresses, IP ranges, or IP subnets. This does not + work if the server is behind a reverse proxy, NAT, etc. because the address + checked against the block list is the address of the proxy, or the one + specified by the NAT. * `connectionListener` {Function} Automatically set as a listener for the [`'connection'`][] event. diff --git a/lib/net.js b/lib/net.js index e438c1c8e781b3..de726e144156d6 100644 --- a/lib/net.js +++ b/lib/net.js @@ -1791,6 +1791,13 @@ function Server(options, connectionListener) { this.keepAlive = Boolean(options.keepAlive); this.keepAliveInitialDelay = ~~(options.keepAliveInitialDelay / 1000); this.highWaterMark = options.highWaterMark ?? getDefaultHighWaterMark(); + if (options.blockList) { + // TODO: use BlockList.isBlockList (https://github.com/nodejs/node/pull/56078) + if (!(options.blockList instanceof module.exports.BlockList)) { + throw new ERR_INVALID_ARG_TYPE('options.blockList', 'net.BlockList', options.blockList); + } + this.blockList = options.blockList; + } } ObjectSetPrototypeOf(Server.prototype, EventEmitter.prototype); ObjectSetPrototypeOf(Server, EventEmitter); @@ -2239,7 +2246,15 @@ function onconnection(err, clientHandle) { clientHandle.close(); return; } - + if (self.blockList && typeof clientHandle.getpeername === 'function') { + const remoteInfo = { __proto__: null }; + clientHandle.getpeername(remoteInfo); + const addressType = isIP(remoteInfo.address); + if (addressType && self.blockList.check(remoteInfo.address, `ipv${addressType}`)) { + clientHandle.close(); + return; + } + } const socket = new Socket({ handle: clientHandle, allowHalfOpen: self.allowHalfOpen, diff --git a/test/parallel/test-net-server-blocklist.js b/test/parallel/test-net-server-blocklist.js new file mode 100644 index 00000000000000..8f310bd6253039 --- /dev/null +++ b/test/parallel/test-net-server-blocklist.js @@ -0,0 +1,19 @@ +'use strict'; +const common = require('../common'); +const net = require('net'); + +const blockList = new net.BlockList(); +blockList.addAddress(common.localhostIPv4); + +const server = net.createServer({ blockList }, common.mustNotCall()); +server.listen(0, common.localhostIPv4, common.mustCall(() => { + const adddress = server.address(); + const socket = net.connect({ + localAddress: common.localhostIPv4, + host: adddress.address, + port: adddress.port + }); + socket.on('close', common.mustCall(() => { + server.close(); + })); +}));