Skip to content

Commit

Permalink
net: support blocklist for net.Server
Browse files Browse the repository at this point in the history
  • Loading branch information
theanarkh committed Nov 29, 2024
1 parent 4cf6fab commit a1321f0
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 1 deletion.
5 changes: 5 additions & 0 deletions doc/api/net.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
17 changes: 16 additions & 1 deletion lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
19 changes: 19 additions & 0 deletions test/parallel/test-net-server-blocklist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict';

Check failure on line 1 in test/parallel/test-net-server-blocklist.js

View workflow job for this annotation

GitHub Actions / test-linux

--- stderr --- node:events:491 throw er; // Unhandled 'error' event ^ Error: bind EINVAL 127.0.0.1 at internalConnect (node:net:1066:18) at defaultTriggerAsyncIdScope (node:internal/async_hooks:464:18) at GetAddrInfoReqWrap.emitLookup [as callback] (node:net:1410:9) at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:111:8) Emitted 'error' event on Socket instance at: at emitErrorNT (node:internal/streams/destroy:170:8) at emitErrorCloseNT (node:internal/streams/destroy:129:3) at process.processTicksAndRejections (node:internal/process/task_queues:90:21) { errno: -22, code: 'EINVAL', syscall: 'bind', address: '127.0.0.1' } Node.js v24.0.0-pre Command: out/Release/node --test-reporter=spec --test-reporter-destination=stdout --test-reporter=./tools/github_reporter/index.js --test-reporter-destination=stdout /home/runner/work/node/node/test/parallel/test-net-server-blocklist.js

Check failure on line 1 in test/parallel/test-net-server-blocklist.js

View workflow job for this annotation

GitHub Actions / test-macOS

--- stderr --- node:events:491 throw er; // Unhandled 'error' event ^ Error: bind EINVAL 127.0.0.1 at internalConnect (node:net:1066:18) at defaultTriggerAsyncIdScope (node:internal/async_hooks:464:18) at GetAddrInfoReqWrap.emitLookup [as callback] (node:net:1410:9) at GetAddrInfoReqWrap.onlookup [as oncomplete] (node:dns:111:8) Emitted 'error' event on Socket instance at: at emitErrorNT (node:internal/streams/destroy:170:8) at emitErrorCloseNT (node:internal/streams/destroy:129:3) at process.processTicksAndRejections (node:internal/process/task_queues:90:21) { errno: -22, code: 'EINVAL', syscall: 'bind', address: '127.0.0.1' } Node.js v24.0.0-pre Command: out/Release/node --test-reporter=spec --test-reporter-destination=stdout --test-reporter=./tools/github_reporter/index.js --test-reporter-destination=stdout /Users/runner/work/node/node/test/parallel/test-net-server-blocklist.js
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.mustCall(() => {
const adddress = server.address();
const socket = net.connect({
localAddress: common.localhostIPv4,
host: adddress.host,
port: adddress.port
});
socket.on('close', common.mustCall(() => {
server.close();
}));
}));

0 comments on commit a1321f0

Please sign in to comment.