Skip to content

Commit ee0fcce

Browse files
feat: add intrinsic support for SOCKS proxies (#1966)
* Socks proxy support for TCP and TLS connections. * Documentation. * Ignore socks for UNIX domain sockets. * Avoid bundling dead code. * Naming. * Update readme. * Update lock file. * Simplify. Co-authored-by: Daniel Lando <daniel.sorridi@gmail.com> * Trade duplexify against home-grown wrapper. * Paranoia, linter. * Minor cleanup. * Tests. * Use a fixed port for the tests. * It seems TCP RST causes the remote to close without EOF on Linux -> test is useless on Linux. * Switch back to dynamic port allocation. --------- Co-authored-by: Daniel Lando <daniel.sorridi@gmail.com>
1 parent 6ee354b commit ee0fcce

File tree

10 files changed

+814
-24
lines changed

10 files changed

+814
-24
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,8 @@ The arguments are:
429429
CONNACK is received
430430
- `username`: the username required by your broker, if any
431431
- `password`: the password required by your broker, if any
432+
- `socksProxy`: establish TCP and TLS connections via a socks proxy (URL, supported protocols are `socks5://`, `socks5h://`, `socks4://`, `socks4a://`)
433+
- `socksTimeout`: timeout for connecting to the socks proxy
432434
- `incomingStore`: a [Store](#store) for the incoming packets
433435
- `outgoingStore`: a [Store](#store) for the outgoing packets
434436
- `queueQoSZero`: if connection is broken, queue outgoing QoS zero messages (default `true`)
@@ -486,6 +488,8 @@ The arguments are:
486488
- `forceNativeWebSocket`: set to true if you're having detection issues (i.e. the `ws does not work in the browser` exception) to force the use of native WebSocket. It is important to note that if set to true for the first client created, then all the clients will use native WebSocket. And conversely, if not set or set to false, all will use the detection result.
487489
- `unixSocket`: if you want to connect to a unix socket, set this to true
488490
491+
Instead of setting `socksProxy` you can also supple the same parameter via the environment variable `MQTTJS_SOCKS_PROXY`.
492+
489493
In case mqtts (mqtt over tls) is required, the `options` object is passed through to [`tls.connect()`](http://nodejs.org/api/tls.html#tls_tls_connect_options_callback). If using a **self-signed certificate**, set `rejectUnauthorized: false`. However, be cautious as this exposes you to potential man in the middle attacks and isn't recommended for production.
490494

491495
For those supporting multiple TLS protocols on a single port, like MQTTS and MQTT over WSS, utilize the `ALPNProtocols` option. This lets you define the Application Layer Protocol Negotiation (ALPN) protocol. You can set `ALPNProtocols` as a string array, Buffer, or Uint8Array based on your setup.

esbuild.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,26 @@ const options = {
4444
)
4545
}
4646
},
47+
{
48+
name: 'resolve-socks',
49+
setup(build) {
50+
// socks is not supported in the browser and adds several 100kb to the build, so stub it
51+
build.onResolve({ filter: /socks$/ }, args => {
52+
return {
53+
path: args.path,
54+
namespace: 'socks-stub'
55+
}
56+
})
57+
58+
build.onLoad({ filter: /.*/, namespace: 'socks-stub' }, args => {
59+
return {
60+
contents: 'module.exports = {}',
61+
loader: 'js'
62+
}
63+
}
64+
)
65+
}
66+
},
4767
],
4868
}
4969

package-lock.json

Lines changed: 14 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@
124124
"readable-stream": "^4.7.0",
125125
"reinterval": "^1.1.0",
126126
"rfdc": "^1.4.1",
127+
"socks": "^2.8.3",
127128
"split2": "^4.2.0",
128129
"worker-timers": "^7.1.8",
129130
"ws": "^8.18.0"

src/lib/client.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ export interface IClientOptions extends ISecureClientOptions {
140140
query?: Record<string, string>
141141
/** Auth string in the format <username>:<password> */
142142
auth?: string
143+
/** Optional SOCKS proxy to use for TCP / TLS connections , i.e. socks5://localhost:1333, socks4://localhost:1333, socks5h://localhost:1333 . Default is socks5h. */
144+
socksProxy?: string
145+
/** Timeout for establishing a socks connection */
146+
socksTimeout?: number
143147
/** Custom ack handler */
144148
customHandleAcks?: AckHandler
145149
/** Broker port */

src/lib/connect/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ function connect(
104104
opts.clientId = opts.query.clientId
105105
}
106106

107+
if (isBrowser || opts.unixSocket) {
108+
opts.socksProxy = undefined
109+
} else if (
110+
opts.socksProxy === undefined &&
111+
typeof process !== 'undefined'
112+
) {
113+
opts.socksProxy = process.env['MQTTJS_SOCKS_PROXY']
114+
}
115+
107116
if (opts.cert && opts.key) {
108117
if (opts.protocol) {
109118
if (['mqtts', 'wss', 'wxs', 'alis'].indexOf(opts.protocol) === -1) {

0 commit comments

Comments
 (0)