From 06c4567ffde9bdbc12e2b1a676900dba69867e24 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Fri, 9 Oct 2026 10:05:53 +0000 Subject: [PATCH] net: fail closed when BlockList peer address is unavailable When a net.Server is configured with a `blockList`, the peer address is looked up with getpeername() and checked before the connection is accepted. If the peer address cannot be obtained (for example, the connection was reset before getpeername(), causing uv_tcp_getpeername() to return ENOTCONN), the access-control check was silently skipped and the connection proceeded, allowing a blocked peer to reach the application's 'connection' handler (fail open). Fail closed: when a BlockList is configured but the peer address cannot be determined, close the connection instead of bypassing the check. A connection whose peer address cannot be obtained cannot be proven to be allowed, so it must be refused. Ref: https://github.com/nodejs/node/issues/66422 Ref: https://github.com/libuv/libuv/pull/5337 Signed-off-by: Matteo Collina Assisted-by: pi --- lib/net.js | 5 ++- .../test-net-server-blocklist-fail-closed.js | 33 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-net-server-blocklist-fail-closed.js diff --git a/lib/net.js b/lib/net.js index 8ec389cf2dc4..7334d4369679 100644 --- a/lib/net.js +++ b/lib/net.js @@ -2826,7 +2826,10 @@ function onconnection(err, clientHandle) { const remoteInfo = { __proto__: null }; clientHandle.getpeername(remoteInfo); const addressType = isIP(remoteInfo.address); - if (addressType && self.blockList.check(remoteInfo.address, `ipv${addressType}`)) { + // Fail closed: if a BlockList is configured but the peer address cannot + // be obtained (e.g. the connection was reset before getpeername()), + // refuse the connection instead of silently bypassing the access control. + if (!addressType || self.blockList.check(remoteInfo.address, `ipv${addressType}`)) { clientHandle.close(); return; } diff --git a/test/parallel/test-net-server-blocklist-fail-closed.js b/test/parallel/test-net-server-blocklist-fail-closed.js new file mode 100644 index 000000000000..cb2ce18bde22 --- /dev/null +++ b/test/parallel/test-net-server-blocklist-fail-closed.js @@ -0,0 +1,33 @@ +'use strict'; +const common = require('../common'); +const net = require('net'); + +const blockList = new net.BlockList(); +blockList.addCIDR('0.0.0.0/0'); +blockList.addCIDR('::/0'); + +// A connection whose peer address cannot be determined (e.g. it was reset +// before getpeername()) must be rejected when a BlockList is configured, +// rather than being delivered to the application (fail closed). +const server = net.createServer({ blockList }, common.mustNotCall()); + +server.listen(0, common.mustCall(() => { + const socket = net.connect(server.address().port); + socket.on('error', () => {}); +})); + +const onconnection = server._handle.onconnection; +server._handle.onconnection = common.mustCall((err, clientHandle) => { + const close = clientHandle.close; + // Simulate the reset-before-getpeername() condition: onconnection() is + // unable to obtain a valid peer address from the accepted connection. + clientHandle.getpeername = function(remoteInfo) { + remoteInfo.address = undefined; + }; + clientHandle.close = common.mustCall(() => { + clientHandle.close = close; + close.call(clientHandle); + server.close(); + }); + onconnection.call(server._handle, err, clientHandle); +});