Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dgram: support blocklist in udp #56087

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/api/dgram.md
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,13 @@ changes:
* `sendBufferSize` {number} Sets the `SO_SNDBUF` socket value.
* `lookup` {Function} Custom lookup function. **Default:** [`dns.lookup()`][].
* `signal` {AbortSignal} An AbortSignal that may be used to close a socket.
* `receiveBlockList` {net.BlockList} `receiveBlockList` can be used for discarding
inbound datagram 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.
* `sendBlockList` {net.BlockList} `sendBlockList` can be used for disabling outbound
access to specific IP addresses, IP ranges, or IP subnets.
* `callback` {Function} Attached as a listener for `'message'` events. Optional.
* Returns: {dgram.Socket}

Expand Down
30 changes: 29 additions & 1 deletion lib/dgram.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const {
_createSocketHandle,
newHandle,
} = require('internal/dgram');
const { isIP } = require('internal/net');
const {
isInt32,
validateAbortSignal,
Expand Down Expand Up @@ -104,6 +105,8 @@ function Socket(type, listener) {
let lookup;
let recvBufferSize;
let sendBufferSize;
let receiveBlockList;
let sendBlockList;

let options;
if (type !== null && typeof type === 'object') {
Expand All @@ -112,6 +115,14 @@ function Socket(type, listener) {
lookup = options.lookup;
recvBufferSize = options.recvBufferSize;
sendBufferSize = options.sendBufferSize;
// TODO: validate the params
// https://github.com/nodejs/node/pull/56078
if (options.receiveBlockList) {
receiveBlockList = options.receiveBlockList;
}
if (options.sendBlockList) {
sendBlockList = options.sendBlockList;
}
}

const handle = newHandle(type, lookup);
Expand All @@ -134,6 +145,8 @@ function Socket(type, listener) {
ipv6Only: options?.ipv6Only,
recvBufferSize,
sendBufferSize,
receiveBlockList,
sendBlockList,
};

if (options?.signal !== undefined) {
Expand Down Expand Up @@ -432,7 +445,10 @@ function doConnect(ex, self, ip, address, port, callback) {
const state = self[kStateSymbol];
if (!state.handle)
return;

if (!ex && state.sendBlockList?.check(ip, `ipv${isIP(ip)}`)) {
// TODO
ex = new ERR_SOCKET_DGRAM_IS_CONNECTED();
}
if (!ex) {
const err = state.handle.connect(ip, port);
if (err) {
Expand Down Expand Up @@ -696,6 +712,14 @@ function doSend(ex, self, ip, list, address, port, callback) {
return;
}

if (port && state.sendBlockList?.check(ip, `ipv${isIP(ip)}`)) {
if (callback) {
// TODO
process.nextTick(callback, new ERR_SOCKET_DGRAM_IS_CONNECTED());
}
return;
}

const req = new SendWrap();
req.list = list; // Keep reference alive.
req.address = address;
Expand Down Expand Up @@ -944,6 +968,10 @@ function onMessage(nread, handle, buf, rinfo) {
if (nread < 0) {
return self.emit('error', new ErrnoException(nread, 'recvmsg'));
}
if (self[kStateSymbol]?.receiveBlockList?.check(rinfo.address,
rinfo.family?.toLocaleLowerCase())) {
return;
}
rinfo.size = buf.length; // compatibility
self.emit('message', buf, rinfo);
}
Expand Down
49 changes: 49 additions & 0 deletions test/parallel/test-dgram-blocklist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const dgram = require('dgram');
const net = require('net');

{
const blockList = new net.BlockList();
blockList.addAddress(common.localhostIPv4);

const connectSocket = dgram.createSocket({ type: 'udp4', sendBlockList: blockList });
connectSocket.connect(9999, common.localhostIPv4, common.mustCall((err) => {
assert.ok(err);
connectSocket.close();
}));
}

{
const blockList = new net.BlockList();
blockList.addAddress(common.localhostIPv4);
const sendSocket = dgram.createSocket({ type: 'udp4', sendBlockList: blockList });
sendSocket.send('hello', 9999, common.localhostIPv4, common.mustCall((err) => {
assert.ok(err);
sendSocket.close();
}));
}

{
const blockList = new net.BlockList();
blockList.addAddress(common.localhostIPv4);
const receiveSocket = dgram.createSocket({ type: 'udp4', receiveBlockList: blockList });
// Hack to close the socket
const check = blockList.check;
blockList.check = function() {
process.nextTick(() => {
receiveSocket.close();
});
return check.apply(this, arguments);
};
receiveSocket.on('message', common.mustNotCall());
receiveSocket.bind(0, common.localhostIPv4, common.mustCall(() => {
const addressInfo = receiveSocket.address();
const client = dgram.createSocket('udp4');
client.send('hello', addressInfo.port, addressInfo.address, common.mustCall((err) => {
assert.ok(!err);
client.close();
}));
}));
}