proxy-chain 3.0.1-beta.5 → 3.0.1-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -6
- package/dist/anonymize_proxy.d.ts +1 -1
- package/dist/anonymize_proxy.js +4 -4
- package/dist/tcp_tunnel_tools.d.ts +2 -0
- package/dist/tcp_tunnel_tools.js +18 -3
- package/dist/utils/validate_listen_port.d.ts +2 -0
- package/dist/utils/validate_listen_port.js +6 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -560,18 +560,23 @@ specified by the `proxyUrl` parameter.
|
|
|
560
560
|
The optional `options` parameter is an object with the following properties:
|
|
561
561
|
- `port: Number` - Enables specifying the local port to listen at. By default `0`,
|
|
562
562
|
which means a random port will be selected.
|
|
563
|
-
- `hostname: String` - Local hostname to listen at. By default `
|
|
563
|
+
- `hostname: String` - Local hostname to listen at. By default `127.0.0.1`.
|
|
564
564
|
- `ignoreProxyCertificate` - For HTTPS proxy, ignore certificate errors in proxy requests. Useful for proxy with self-signed certificate. By default `false`.
|
|
565
565
|
- `verbose: Boolean` - If `true`, the functions logs a lot. By default `false`.
|
|
566
566
|
|
|
567
|
-
The result of the function is a local endpoint in a form of `hostname:port
|
|
567
|
+
The result of the function is a local endpoint in a form of `hostname:port`,
|
|
568
|
+
where `hostname` is the address the tunnel actually bound to. IPv6 addresses are
|
|
569
|
+
bracketed, e.g. `[::1]:56836`.
|
|
570
|
+
|
|
568
571
|
All TCP connections made to the local endpoint will be tunneled through the proxy to the target host and port.
|
|
569
572
|
For example, this is useful if you want to access a certain service from a specific IP address.
|
|
570
573
|
|
|
571
|
-
The tunnel
|
|
574
|
+
The tunnel does not authenticate its clients and forwards the `proxyUrl`
|
|
575
|
+
credentials upstream, which is why it listens on `127.0.0.1` by default. Only
|
|
576
|
+
pass a non-loopback `hostname` if you restrict access to it by other means -
|
|
577
|
+
doing so emits a `ProxyChainSecurityWarning` via `process.emitWarning()`.
|
|
572
578
|
|
|
573
|
-
The
|
|
574
|
-
the path to the local endpoint.
|
|
579
|
+
The tunnel should be eventually closed by calling the `closeTunnel()` function.
|
|
575
580
|
|
|
576
581
|
For more information, read this [blog post](https://blog.apify.com/tunneling-arbitrary-protocols-over-http-proxy-with-static-ip-address-b3a2222191ff).
|
|
577
582
|
|
|
@@ -579,7 +584,7 @@ Example:
|
|
|
579
584
|
|
|
580
585
|
```javascript
|
|
581
586
|
const host = await createTunnel('http://bob:pass123@proxy.example.com:8000', 'service.example.com:356');
|
|
582
|
-
// Prints something like "
|
|
587
|
+
// Prints something like "127.0.0.1:56836"
|
|
583
588
|
console.log(host);
|
|
584
589
|
```
|
|
585
590
|
|
package/dist/anonymize_proxy.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { URL } from 'node:url';
|
|
2
2
|
import { Server, SOCKS_PROTOCOLS } from './server.js';
|
|
3
|
+
import { validateListenPort } from './utils/validate_listen_port.js';
|
|
3
4
|
// Dictionary, key is value returned from anonymizeProxy(), value is Server instance.
|
|
4
5
|
const anonymizedProxyUrlToServer = {};
|
|
5
6
|
/**
|
|
@@ -16,10 +17,9 @@ export const anonymizeProxy = async (options) => {
|
|
|
16
17
|
}
|
|
17
18
|
else {
|
|
18
19
|
proxyUrl = options.url;
|
|
19
|
-
port
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
20
|
+
// Port 0 tells the OS to pick a free ephemeral port, which we read back after `listen()`.
|
|
21
|
+
port = options.port ?? 0;
|
|
22
|
+
validateListenPort(port);
|
|
23
23
|
if (options.ignoreProxyCertificate !== undefined) {
|
|
24
24
|
ignoreProxyCertificate = options.ignoreProxyCertificate;
|
|
25
25
|
}
|
package/dist/tcp_tunnel_tools.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import net from 'node:net';
|
|
2
2
|
import { URL } from 'node:url';
|
|
3
3
|
import { chain } from './chain.js';
|
|
4
|
+
import { validateListenPort } from './utils/validate_listen_port.js';
|
|
4
5
|
const runningServers = {};
|
|
6
|
+
// The tunnel does not authenticate its clients and forwards the proxyUrl credentials
|
|
7
|
+
// upstream, so it must not be reachable off the local machine by default.
|
|
8
|
+
const DEFAULT_LISTEN_HOSTNAME = '127.0.0.1';
|
|
9
|
+
const LOOPBACK_HOSTNAMES = new Set(['localhost', '::1', '0:0:0:0:0:0:0:1']);
|
|
10
|
+
const isLoopbackHostname = (hostname) => {
|
|
11
|
+
const normalized = hostname.toLowerCase();
|
|
12
|
+
return LOOPBACK_HOSTNAMES.has(normalized) || normalized.startsWith('127.');
|
|
13
|
+
};
|
|
5
14
|
const getAddress = (server) => {
|
|
6
15
|
const { address: host, port, family } = server.address();
|
|
7
16
|
if (family === 'IPv6') {
|
|
@@ -21,7 +30,14 @@ export async function createTunnel(proxyUrl, targetHost, options) {
|
|
|
21
30
|
if (!url.port) {
|
|
22
31
|
throw new Error('Missing target port');
|
|
23
32
|
}
|
|
24
|
-
const
|
|
33
|
+
const listenPort = options?.port ?? 0;
|
|
34
|
+
const listenHostname = options?.hostname || DEFAULT_LISTEN_HOSTNAME;
|
|
35
|
+
validateListenPort(listenPort);
|
|
36
|
+
if (!isLoopbackHostname(listenHostname)) {
|
|
37
|
+
process.emitWarning(`The tunnel is listening on "${listenHostname}", so it may be reachable from other machines.`
|
|
38
|
+
+ ' It does not authenticate its clients and forwards the proxyUrl credentials upstream.', 'ProxyChainSecurityWarning');
|
|
39
|
+
}
|
|
40
|
+
const verbose = options?.verbose ?? false;
|
|
25
41
|
const server = net.createServer();
|
|
26
42
|
const log = (...args) => {
|
|
27
43
|
// eslint-disable-next-line no-console
|
|
@@ -51,8 +67,7 @@ export async function createTunnel(proxyUrl, targetHost, options) {
|
|
|
51
67
|
});
|
|
52
68
|
const promise = new Promise((resolve, reject) => {
|
|
53
69
|
server.once('error', reject);
|
|
54
|
-
|
|
55
|
-
server.listen(0, () => {
|
|
70
|
+
server.listen(listenPort, listenHostname, () => {
|
|
56
71
|
const address = getAddress(server);
|
|
57
72
|
server.off('error', reject);
|
|
58
73
|
runningServers[address] = { server, connections: new Set() };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Throws if `port` is not a valid TCP port number (0-65535). */
|
|
2
|
+
export const validateListenPort = (port) => {
|
|
3
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
4
|
+
throw new Error(`The "port" option must be an integer between 0 and 65535 (was ${port})`);
|
|
5
|
+
}
|
|
6
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proxy-chain",
|
|
3
|
-
"version": "3.0.1-beta.
|
|
3
|
+
"version": "3.0.1-beta.6",
|
|
4
4
|
"description": "Node.js implementation of a proxy server (think Squid) with support for SSL, authentication, upstream proxy chaining, and protocol tunneling.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|