Skip to content

Commit 269cab6

Browse files
authored
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: #66422 Ref: libuv/libuv#5337 Signed-off-by: Matteo Collina <hello@matteocollina.com> Assisted-by: pi PR-URL: #66640 Refs: #66422 Refs: libuv/libuv#5337 Reviewed-By: Tim Perry <pimterry@gmail.com>
1 parent b5b07a0 commit 269cab6

2 files changed

Lines changed: 37 additions & 1 deletion

File tree

‎lib/net.js‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2935,7 +2935,10 @@ function onconnection(err, clientHandle) {
29352935
const remoteInfo = { __proto__: null };
29362936
clientHandle.getpeername(remoteInfo);
29372937
const addressType = isIP(remoteInfo.address);
2938-
if (addressType && self.blockList.check(remoteInfo.address, `ipv${addressType}`)) {
2938+
// Fail closed: if a BlockList is configured but the peer address cannot
2939+
// be obtained (e.g. the connection was reset before getpeername()),
2940+
// refuse the connection instead of silently bypassing the access control.
2941+
if (!addressType || self.blockList.check(remoteInfo.address, `ipv${addressType}`)) {
29392942
clientHandle.close();
29402943
return;
29412944
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
const common = require('../common');
3+
const net = require('net');
4+
5+
const blockList = new net.BlockList();
6+
blockList.addCIDR('0.0.0.0/0');
7+
blockList.addCIDR('::/0');
8+
9+
// A connection whose peer address cannot be determined (e.g. it was reset
10+
// before getpeername()) must be rejected when a BlockList is configured,
11+
// rather than being delivered to the application (fail closed).
12+
const server = net.createServer({ blockList }, common.mustNotCall());
13+
14+
server.listen(0, common.mustCall(() => {
15+
const socket = net.connect(server.address().port);
16+
socket.on('error', () => {});
17+
}));
18+
19+
const onconnection = server._handle.onconnection;
20+
server._handle.onconnection = common.mustCall((err, clientHandle) => {
21+
const close = clientHandle.close;
22+
// Simulate the reset-before-getpeername() condition: onconnection() is
23+
// unable to obtain a valid peer address from the accepted connection.
24+
clientHandle.getpeername = function(remoteInfo) {
25+
remoteInfo.address = undefined;
26+
};
27+
clientHandle.close = common.mustCall(() => {
28+
clientHandle.close = close;
29+
close.call(clientHandle);
30+
server.close();
31+
});
32+
onconnection.call(server._handle, err, clientHandle);
33+
});

0 commit comments

Comments
 (0)