From 1bb4c6746a2ad322aaee74c31c92d8d5518ee09e 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 | 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 7d8a27bf0b1769..b4076b54fb2a9d 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 blocklist 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 52085df6ba0574..94f99b75ea5c76 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..3556f1d49ad95b --- /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(); + })); +}));