From 4ecdf0379be7e16d19d84018d1d00d1ebb70c518 Mon Sep 17 00:00:00 2001 From: theanarkh Date: Sat, 30 Nov 2024 00:22:33 +0800 Subject: [PATCH] net: support blocklist for net.Server --- doc/api/net.md | 2 ++ lib/net.js | 19 ++++++++++++++++++- test/parallel/test-net-server-blocklist.js | 19 +++++++++++++++++++ 3 files changed, 39 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 7d8a27bf0b1769..6cc79923f5f243 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -1713,6 +1713,8 @@ 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. * `connectionListener` {Function} Automatically set as a listener for the [`'connection'`][] event. diff --git a/lib/net.js b/lib/net.js index 52085df6ba0574..047749c0e5dae3 100644 --- a/lib/net.js +++ b/lib/net.js @@ -204,6 +204,9 @@ function isPipeName(s) { return typeof s === 'string' && toNumber(s) === false; } +function isBlockList(obj) { + return obj instanceof module.exports.BlockList; +} /** * Creates a new TCP or IPC server * @param {{ @@ -1791,6 +1794,12 @@ function Server(options, connectionListener) { this.keepAlive = Boolean(options.keepAlive); this.keepAliveInitialDelay = ~~(options.keepAliveInitialDelay / 1000); this.highWaterMark = options.highWaterMark ?? getDefaultHighWaterMark(); + if (options.blocklist) { + if (!isBlockList(options.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 +2248,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..617c1e70b8d200 --- /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('127.0.0.1'); + +const server = net.createServer({ blocklist }, common.mustNotCall()); +server.listen(0, common.mustCall(() => { + const adddress = server.address(); + const socket = net.connect({ + localAddress: '127.0.0.1', + host: adddress.host, + port: adddress.port + }); + socket.on('close', common.mustCall(() => { + server.close(); + })); +}));