Skip to content

Commit 59cae91

Browse files
theanarkhaduh95
authored andcommitted
dgram: support blocklist in udp
PR-URL: #56087 Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
1 parent f94f210 commit 59cae91

File tree

3 files changed

+92
-1
lines changed

3 files changed

+92
-1
lines changed

doc/api/dgram.md

Lines changed: 7 additions & 0 deletions
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

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const {
4141
ERR_BUFFER_OUT_OF_BOUNDS,
4242
ERR_INVALID_ARG_TYPE,
4343
ERR_INVALID_FD_TYPE,
44+
ERR_IP_BLOCKED,
4445
ERR_MISSING_ARGS,
4546
ERR_SOCKET_ALREADY_BOUND,
4647
ERR_SOCKET_BAD_BUFFER_SIZE,
@@ -55,6 +56,7 @@ const {
5556
_createSocketHandle,
5657
newHandle,
5758
} = require('internal/dgram');
59+
const { isIP } = require('internal/net');
5860
const {
5961
isInt32,
6062
validateAbortSignal,
@@ -99,12 +101,18 @@ let _cluster = null;
99101
function lazyLoadCluster() {
100102
return _cluster ??= require('cluster');
101103
}
104+
let _blockList = null;
105+
function lazyLoadBlockList() {
106+
return _blockList ??= require('internal/blocklist').BlockList;
107+
}
102108

103109
function Socket(type, listener) {
104110
FunctionPrototypeCall(EventEmitter, this);
105111
let lookup;
106112
let recvBufferSize;
107113
let sendBufferSize;
114+
let receiveBlockList;
115+
let sendBlockList;
108116

109117
let options;
110118
if (type !== null && typeof type === 'object') {
@@ -119,6 +127,18 @@ function Socket(type, listener) {
119127
}
120128
recvBufferSize = options.recvBufferSize;
121129
sendBufferSize = options.sendBufferSize;
130+
if (options.receiveBlockList) {
131+
if (!lazyLoadBlockList().isBlockList(options.receiveBlockList)) {
132+
throw new ERR_INVALID_ARG_TYPE('options.receiveBlockList', 'net.BlockList', options.receiveBlockList);
133+
}
134+
receiveBlockList = options.receiveBlockList;
135+
}
136+
if (options.sendBlockList) {
137+
if (!lazyLoadBlockList().isBlockList(options.sendBlockList)) {
138+
throw new ERR_INVALID_ARG_TYPE('options.sendBlockList', 'net.BlockList', options.sendBlockList);
139+
}
140+
sendBlockList = options.sendBlockList;
141+
}
122142
}
123143

124144
const handle = newHandle(type, lookup);
@@ -141,6 +161,8 @@ function Socket(type, listener) {
141161
ipv6Only: options?.ipv6Only,
142162
recvBufferSize,
143163
sendBufferSize,
164+
receiveBlockList,
165+
sendBlockList,
144166
};
145167

146168
if (options?.signal !== undefined) {
@@ -439,7 +461,9 @@ function doConnect(ex, self, ip, address, port, callback) {
439461
const state = self[kStateSymbol];
440462
if (!state.handle)
441463
return;
442-
464+
if (!ex && state.sendBlockList?.check(ip, `ipv${isIP(ip)}`)) {
465+
ex = new ERR_IP_BLOCKED(ip);
466+
}
443467
if (!ex) {
444468
const err = state.handle.connect(ip, port);
445469
if (err) {
@@ -703,6 +727,13 @@ function doSend(ex, self, ip, list, address, port, callback) {
703727
return;
704728
}
705729

730+
if (ip && state.sendBlockList?.check(ip, `ipv${isIP(ip)}`)) {
731+
if (callback) {
732+
process.nextTick(callback, new ERR_IP_BLOCKED(ip));
733+
}
734+
return;
735+
}
736+
706737
const req = new SendWrap();
707738
req.list = list; // Keep reference alive.
708739
req.address = address;
@@ -951,6 +982,10 @@ function onMessage(nread, handle, buf, rinfo) {
951982
if (nread < 0) {
952983
return self.emit('error', new ErrnoException(nread, 'recvmsg'));
953984
}
985+
if (self[kStateSymbol]?.receiveBlockList?.check(rinfo.address,
986+
rinfo.family?.toLocaleLowerCase())) {
987+
return;
988+
}
954989
rinfo.size = buf.length; // compatibility
955990
self.emit('message', buf, rinfo);
956991
}

test/parallel/test-dgram-blocklist.js

Lines changed: 49 additions & 0 deletions
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.code === 'ERR_IP_BLOCKED', 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.code === 'ERR_IP_BLOCKED', 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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy