Skip to content

Commit 51c92f2

Browse files
committed
dgram: support blocklist in udp
1 parent 4cf6fab commit 51c92f2

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

doc/api/dgram.md

+7
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,13 @@ changes:
957957
* `sendBufferSize` {number} Sets the `SO_SNDBUF` socket value.
958958
* `lookup` {Function} Custom lookup function. **Default:** [`dns.lookup()`][].
959959
* `signal` {AbortSignal} An AbortSignal that may be used to close a socket.
960+
* `receiveBlockList` {net.BlockList} `receiveBlockList` can be used for discarding
961+
inbound datagram to specific IP addresses, IP ranges, or IP subnets. This does not
962+
work if the server is behind a reverse proxy, NAT, etc. because the address
963+
checked against the blocklist is the address of the proxy, or the one
964+
specified by the NAT.
965+
* `sendBlockList` {net.BlockList} `sendBlockList` can be used for disabling outbound
966+
access to specific IP addresses, IP ranges, or IP subnets.
960967
* `callback` {Function} Attached as a listener for `'message'` events. Optional.
961968
* Returns: {dgram.Socket}
962969

lib/dgram.js

+29-1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ const {
5555
_createSocketHandle,
5656
newHandle,
5757
} = require('internal/dgram');
58+
const { isIP } = require('internal/net');
5859
const {
5960
isInt32,
6061
validateAbortSignal,
@@ -104,6 +105,8 @@ function Socket(type, listener) {
104105
let lookup;
105106
let recvBufferSize;
106107
let sendBufferSize;
108+
let receiveBlockList;
109+
let sendBlockList;
107110

108111
let options;
109112
if (type !== null && typeof type === 'object') {
@@ -112,6 +115,14 @@ function Socket(type, listener) {
112115
lookup = options.lookup;
113116
recvBufferSize = options.recvBufferSize;
114117
sendBufferSize = options.sendBufferSize;
118+
// TODO: validate the params
119+
// https://github.com/nodejs/node/pull/56078
120+
if (options.receiveBlockList) {
121+
receiveBlockList = options.receiveBlockList;
122+
}
123+
if (options.sendBlockList) {
124+
sendBlockList = options.sendBlockList;
125+
}
115126
}
116127

117128
const handle = newHandle(type, lookup);
@@ -134,6 +145,8 @@ function Socket(type, listener) {
134145
ipv6Only: options?.ipv6Only,
135146
recvBufferSize,
136147
sendBufferSize,
148+
receiveBlockList,
149+
sendBlockList,
137150
};
138151

139152
if (options?.signal !== undefined) {
@@ -432,7 +445,10 @@ function doConnect(ex, self, ip, address, port, callback) {
432445
const state = self[kStateSymbol];
433446
if (!state.handle)
434447
return;
435-
448+
if (!ex && state.sendBlockList?.check(ip, `ipv${isIP(ip)}`)) {
449+
// TODO
450+
ex = new ERR_SOCKET_DGRAM_IS_CONNECTED();
451+
}
436452
if (!ex) {
437453
const err = state.handle.connect(ip, port);
438454
if (err) {
@@ -696,6 +712,14 @@ function doSend(ex, self, ip, list, address, port, callback) {
696712
return;
697713
}
698714

715+
if (port && state.sendBlockList?.check(ip, `ipv${isIP(ip)}`)) {
716+
if (callback) {
717+
// TODO
718+
process.nextTick(callback, new ERR_SOCKET_DGRAM_IS_CONNECTED());
719+
}
720+
return;
721+
}
722+
699723
const req = new SendWrap();
700724
req.list = list; // Keep reference alive.
701725
req.address = address;
@@ -944,6 +968,10 @@ function onMessage(nread, handle, buf, rinfo) {
944968
if (nread < 0) {
945969
return self.emit('error', new ErrnoException(nread, 'recvmsg'));
946970
}
971+
if (self[kStateSymbol]?.receiveBlockList?.check(rinfo.address,
972+
rinfo.family?.toLocaleLowerCase())) {
973+
return;
974+
}
947975
rinfo.size = buf.length; // compatibility
948976
self.emit('message', buf, rinfo);
949977
}

test/parallel/test-dgram-blocklist.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const dgram = require('dgram');
5+
const net = require('net');
6+
7+
{
8+
const blockList = new net.BlockList();
9+
blockList.addAddress(common.localhostIPv4);
10+
11+
const connectSocket = dgram.createSocket({ type: 'udp4', sendBlockList: blockList });
12+
connectSocket.connect(9999, common.localhostIPv4, common.mustCall((err) => {
13+
assert.ok(err);
14+
connectSocket.close();
15+
}));
16+
}
17+
18+
{
19+
const blockList = new net.BlockList();
20+
blockList.addAddress(common.localhostIPv4);
21+
const sendSocket = dgram.createSocket({ type: 'udp4', sendBlockList: blockList });
22+
sendSocket.send('hello', 9999, common.localhostIPv4, common.mustCall((err) => {
23+
assert.ok(err);
24+
sendSocket.close();
25+
}));
26+
}
27+
28+
{
29+
const blockList = new net.BlockList();
30+
blockList.addAddress(common.localhostIPv4);
31+
const receiveSocket = dgram.createSocket({ type: 'udp4', receiveBlockList: blockList });
32+
// Hack to close the socket
33+
const check = blockList.check;
34+
blockList.check = function() {
35+
process.nextTick(() => {
36+
receiveSocket.close();
37+
});
38+
return check.apply(this, arguments);
39+
};
40+
receiveSocket.on('message', common.mustNotCall());
41+
receiveSocket.bind(0, common.localhostIPv4, common.mustCall(() => {
42+
const addressInfo = receiveSocket.address();
43+
const client = dgram.createSocket('udp4');
44+
client.send('hello', addressInfo.port, addressInfo.address, common.mustCall((err) => {
45+
assert.ok(!err);
46+
client.close();
47+
}));
48+
}));
49+
}

0 commit comments

Comments
 (0)