@push.rocks/smartproxy 3.2.0 → 3.3.0
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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/smartproxy.plugins.d.ts +2 -1
- package/dist_ts/smartproxy.plugins.js +3 -2
- package/dist_ts/smartproxy.portproxy.d.ts +13 -1
- package/dist_ts/smartproxy.portproxy.js +38 -4
- package/package.json +4 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/smartproxy.plugins.ts +2 -1
- package/ts/smartproxy.portproxy.ts +54 -3
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@push.rocks/smartproxy',
|
|
6
|
-
version: '3.
|
|
6
|
+
version: '3.3.0',
|
|
7
7
|
description: 'a proxy for handling high workloads of proxying'
|
|
8
8
|
};
|
|
9
9
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLGlEQUFpRDtDQUMvRCxDQUFBIn0=
|
|
@@ -13,4 +13,5 @@ import * as smartstring from '@push.rocks/smartstring';
|
|
|
13
13
|
export { lik, smartdelay, smartrequest, smartpromise, smartstring };
|
|
14
14
|
import * as ws from 'ws';
|
|
15
15
|
import wsDefault from 'ws';
|
|
16
|
-
|
|
16
|
+
import { minimatch } from 'minimatch';
|
|
17
|
+
export { wsDefault, ws, minimatch };
|
|
@@ -17,5 +17,6 @@ export { lik, smartdelay, smartrequest, smartpromise, smartstring };
|
|
|
17
17
|
// third party scope
|
|
18
18
|
import * as ws from 'ws';
|
|
19
19
|
import wsDefault from 'ws';
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
import { minimatch } from 'minimatch';
|
|
21
|
+
export { wsDefault, ws, minimatch };
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwcm94eS5wbHVnaW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRwcm94eS5wbHVnaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLG9CQUFvQjtBQUNwQixPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUM3QixPQUFPLEtBQUssS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMvQixPQUFPLEtBQUssR0FBRyxNQUFNLEtBQUssQ0FBQztBQUMzQixPQUFPLEtBQUssR0FBRyxNQUFNLEtBQUssQ0FBQztBQUUzQixPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUM7QUFFakMsZ0JBQWdCO0FBQ2hCLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDO0FBRW5CLGtCQUFrQjtBQUNsQixPQUFPLEtBQUssR0FBRyxNQUFNLGlCQUFpQixDQUFDO0FBQ3ZDLE9BQU8sS0FBSyxVQUFVLE1BQU0sd0JBQXdCLENBQUM7QUFDckQsT0FBTyxLQUFLLFlBQVksTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEtBQUssWUFBWSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFFdkQsT0FBTyxFQUFFLEdBQUcsRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUVwRSxvQkFBb0I7QUFDcEIsT0FBTyxLQUFLLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDekIsT0FBTyxTQUFTLE1BQU0sSUFBSSxDQUFDO0FBQzNCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFdEMsT0FBTyxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUUsU0FBUyxFQUFFLENBQUMifQ==
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import * as plugins from './smartproxy.plugins.js';
|
|
2
|
+
import * as tls from 'tls';
|
|
3
|
+
export interface DomainConfig {
|
|
4
|
+
domain: string;
|
|
5
|
+
allowedIPs: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface ProxySettings {
|
|
8
|
+
domains: DomainConfig[];
|
|
9
|
+
sniEnabled?: boolean;
|
|
10
|
+
tlsOptions?: tls.TlsOptions;
|
|
11
|
+
defaultAllowedIPs?: string[];
|
|
12
|
+
}
|
|
2
13
|
export declare class PortProxy {
|
|
3
14
|
netServer: plugins.net.Server;
|
|
4
15
|
fromPort: number;
|
|
5
16
|
toPort: number;
|
|
6
|
-
|
|
17
|
+
settings: ProxySettings;
|
|
18
|
+
constructor(fromPortArg: number, toPortArg: number, settings: ProxySettings);
|
|
7
19
|
start(): Promise<void>;
|
|
8
20
|
stop(): Promise<void>;
|
|
9
21
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as plugins from './smartproxy.plugins.js';
|
|
2
2
|
import * as net from 'net';
|
|
3
|
+
import * as tls from 'tls';
|
|
3
4
|
export class PortProxy {
|
|
4
|
-
constructor(fromPortArg, toPortArg) {
|
|
5
|
+
constructor(fromPortArg, toPortArg, settings) {
|
|
5
6
|
this.fromPort = fromPortArg;
|
|
6
7
|
this.toPort = toPortArg;
|
|
8
|
+
this.settings = settings;
|
|
7
9
|
}
|
|
8
10
|
async start() {
|
|
9
11
|
const cleanUpSockets = (from, to) => {
|
|
@@ -16,8 +18,40 @@ export class PortProxy {
|
|
|
16
18
|
from.destroy();
|
|
17
19
|
to.destroy();
|
|
18
20
|
};
|
|
19
|
-
|
|
20
|
-
.
|
|
21
|
+
const isAllowed = (value, patterns) => {
|
|
22
|
+
return patterns.some(pattern => plugins.minimatch(value, pattern));
|
|
23
|
+
};
|
|
24
|
+
const findMatchingDomain = (serverName) => {
|
|
25
|
+
return this.settings.domains.find(config => plugins.minimatch(serverName, config.domain));
|
|
26
|
+
};
|
|
27
|
+
const server = this.settings.sniEnabled ? tls.createServer(this.settings.tlsOptions || {}) : net.createServer();
|
|
28
|
+
this.netServer = server.on('connection', (from) => {
|
|
29
|
+
const remoteIP = from.remoteAddress || '';
|
|
30
|
+
if (this.settings.sniEnabled && from instanceof tls.TLSSocket) {
|
|
31
|
+
const serverName = from.servername || '';
|
|
32
|
+
const domainConfig = findMatchingDomain(serverName);
|
|
33
|
+
if (!domainConfig) {
|
|
34
|
+
// If no matching domain config found, check default IPs if available
|
|
35
|
+
if (!this.settings.defaultAllowedIPs || !isAllowed(remoteIP, this.settings.defaultAllowedIPs)) {
|
|
36
|
+
console.log(`Connection rejected: No matching domain config for ${serverName} from IP ${remoteIP}`);
|
|
37
|
+
from.end();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Check if IP is allowed for this domain
|
|
43
|
+
if (!isAllowed(remoteIP, domainConfig.allowedIPs)) {
|
|
44
|
+
console.log(`Connection rejected: IP ${remoteIP} not allowed for domain ${serverName}`);
|
|
45
|
+
from.end();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (!this.settings.defaultAllowedIPs || !isAllowed(remoteIP, this.settings.defaultAllowedIPs)) {
|
|
51
|
+
console.log(`Connection rejected: IP ${remoteIP} not allowed for non-SNI connection`);
|
|
52
|
+
from.end();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
21
55
|
const to = net.createConnection({
|
|
22
56
|
host: 'localhost',
|
|
23
57
|
port: this.toPort,
|
|
@@ -61,4 +95,4 @@ export class PortProxy {
|
|
|
61
95
|
await done.promise;
|
|
62
96
|
}
|
|
63
97
|
}
|
|
64
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
98
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRwcm94eS5wb3J0cHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydHByb3h5LnBvcnRwcm94eS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLHlCQUF5QixDQUFDO0FBQ25ELE9BQU8sS0FBSyxHQUFHLE1BQU0sS0FBSyxDQUFDO0FBQzNCLE9BQU8sS0FBSyxHQUFHLE1BQU0sS0FBSyxDQUFDO0FBZTNCLE1BQU0sT0FBTyxTQUFTO0lBTXBCLFlBQVksV0FBbUIsRUFBRSxTQUFpQixFQUFFLFFBQXVCO1FBQ3pFLElBQUksQ0FBQyxRQUFRLEdBQUcsV0FBVyxDQUFDO1FBQzVCLElBQUksQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDO1FBQ3hCLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO0lBQzNCLENBQUM7SUFFTSxLQUFLLENBQUMsS0FBSztRQUNoQixNQUFNLGNBQWMsR0FBRyxDQUFDLElBQXdCLEVBQUUsRUFBc0IsRUFBRSxFQUFFO1lBQzFFLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNYLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNULElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQzFCLEVBQUUsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQ3hCLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNkLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNaLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNmLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNmLENBQUMsQ0FBQztRQUNGLE1BQU0sU0FBUyxHQUFHLENBQUMsS0FBYSxFQUFFLFFBQWtCLEVBQVcsRUFBRTtZQUMvRCxPQUFPLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQyxD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
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@push.rocks/smartproxy",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "a proxy for handling high workloads of proxying",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"@push.rocks/smartstring": "^4.0.15",
|
|
25
25
|
"@tsclass/tsclass": "^4.4.0",
|
|
26
26
|
"@types/ws": "^8.5.14",
|
|
27
|
-
"ws": "^8.18.0"
|
|
27
|
+
"ws": "^8.18.0",
|
|
28
|
+
"minimatch": "^9.0.3",
|
|
29
|
+
"@types/minimatch": "^5.1.2"
|
|
28
30
|
},
|
|
29
31
|
"files": [
|
|
30
32
|
"ts/**/*",
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/smartproxy.plugins.ts
CHANGED
|
@@ -23,5 +23,6 @@ export { lik, smartdelay, smartrequest, smartpromise, smartstring };
|
|
|
23
23
|
// third party scope
|
|
24
24
|
import * as ws from 'ws';
|
|
25
25
|
import wsDefault from 'ws';
|
|
26
|
+
import { minimatch } from 'minimatch';
|
|
26
27
|
|
|
27
|
-
export { wsDefault, ws };
|
|
28
|
+
export { wsDefault, ws, minimatch };
|
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
import * as plugins from './smartproxy.plugins.js';
|
|
2
2
|
import * as net from 'net';
|
|
3
|
+
import * as tls from 'tls';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
export interface DomainConfig {
|
|
7
|
+
domain: string; // glob pattern for domain
|
|
8
|
+
allowedIPs: string[]; // glob patterns for IPs allowed to access this domain
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ProxySettings {
|
|
12
|
+
domains: DomainConfig[];
|
|
13
|
+
sniEnabled?: boolean;
|
|
14
|
+
tlsOptions?: tls.TlsOptions;
|
|
15
|
+
defaultAllowedIPs?: string[]; // Optional default IP patterns if no matching domain found
|
|
16
|
+
}
|
|
3
17
|
|
|
4
18
|
export class PortProxy {
|
|
5
19
|
netServer: plugins.net.Server;
|
|
6
20
|
fromPort: number;
|
|
7
21
|
toPort: number;
|
|
22
|
+
settings: ProxySettings;
|
|
8
23
|
|
|
9
|
-
constructor(fromPortArg: number, toPortArg: number) {
|
|
24
|
+
constructor(fromPortArg: number, toPortArg: number, settings: ProxySettings) {
|
|
10
25
|
this.fromPort = fromPortArg;
|
|
11
26
|
this.toPort = toPortArg;
|
|
27
|
+
this.settings = settings;
|
|
12
28
|
}
|
|
13
29
|
|
|
14
30
|
public async start() {
|
|
@@ -22,8 +38,43 @@ export class PortProxy {
|
|
|
22
38
|
from.destroy();
|
|
23
39
|
to.destroy();
|
|
24
40
|
};
|
|
25
|
-
|
|
26
|
-
.
|
|
41
|
+
const isAllowed = (value: string, patterns: string[]): boolean => {
|
|
42
|
+
return patterns.some(pattern => plugins.minimatch(value, pattern));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const findMatchingDomain = (serverName: string): DomainConfig | undefined => {
|
|
46
|
+
return this.settings.domains.find(config => plugins.minimatch(serverName, config.domain));
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const server = this.settings.sniEnabled ? tls.createServer(this.settings.tlsOptions || {}) : net.createServer();
|
|
50
|
+
|
|
51
|
+
this.netServer = server.on('connection', (from: net.Socket) => {
|
|
52
|
+
const remoteIP = from.remoteAddress || '';
|
|
53
|
+
if (this.settings.sniEnabled && from instanceof tls.TLSSocket) {
|
|
54
|
+
const serverName = (from as any).servername || '';
|
|
55
|
+
const domainConfig = findMatchingDomain(serverName);
|
|
56
|
+
|
|
57
|
+
if (!domainConfig) {
|
|
58
|
+
// If no matching domain config found, check default IPs if available
|
|
59
|
+
if (!this.settings.defaultAllowedIPs || !isAllowed(remoteIP, this.settings.defaultAllowedIPs)) {
|
|
60
|
+
console.log(`Connection rejected: No matching domain config for ${serverName} from IP ${remoteIP}`);
|
|
61
|
+
from.end();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
// Check if IP is allowed for this domain
|
|
66
|
+
if (!isAllowed(remoteIP, domainConfig.allowedIPs)) {
|
|
67
|
+
console.log(`Connection rejected: IP ${remoteIP} not allowed for domain ${serverName}`);
|
|
68
|
+
from.end();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} else if (!this.settings.defaultAllowedIPs || !isAllowed(remoteIP, this.settings.defaultAllowedIPs)) {
|
|
73
|
+
console.log(`Connection rejected: IP ${remoteIP} not allowed for non-SNI connection`);
|
|
74
|
+
from.end();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
27
78
|
const to = net.createConnection({
|
|
28
79
|
host: 'localhost',
|
|
29
80
|
port: this.toPort,
|