From 6fddafe9fd1df138cbb2478e34899214a76b0eca Mon Sep 17 00:00:00 2001 From: Philipp Kunz Date: Tue, 11 Mar 2025 17:50:56 +0000 Subject: [PATCH] feat(PortProxy): Add domain-specific NetworkProxy integration support to PortProxy --- changelog.md | 8 ++++ ts/00_commitinfo_data.ts | 2 +- ts/classes.portproxy.ts | 86 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 89 insertions(+), 7 deletions(-) diff --git a/changelog.md b/changelog.md index 84620e3..70a3294 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2025-03-11 - 3.39.0 - feat(PortProxy) +Add domain-specific NetworkProxy integration support to PortProxy + +- Introduced new properties 'useNetworkProxy' and 'networkProxyPort' in domain configurations. +- Updated forwardToNetworkProxy to accept an optional custom proxy port parameter. +- Enhanced TLS handshake processing to extract SNI and, if a matching domain config specifies NetworkProxy usage, forward the connection using the domain-specific port. +- Refined connection routing logic to check for domain-specific NetworkProxy settings before falling back to default behavior. + ## 2025-03-11 - 3.38.2 - fix(core) No code changes detected; bumping patch version for consistency. diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index fa99d57..8930d0c 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@push.rocks/smartproxy', - version: '3.38.2', + version: '3.39.0', description: 'A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, dynamic routing with authentication options, and automatic ACME certificate management.' } diff --git a/ts/classes.portproxy.ts b/ts/classes.portproxy.ts index 748d388..40b9c71 100644 --- a/ts/classes.portproxy.ts +++ b/ts/classes.portproxy.ts @@ -11,6 +11,10 @@ export interface IDomainConfig { portRanges?: Array<{ from: number; to: number }>; // Optional port ranges // Allow domain-specific timeout override connectionTimeout?: number; // Connection timeout override (ms) + + // NetworkProxy integration options for this specific domain + useNetworkProxy?: boolean; // Whether to use NetworkProxy for this domain + networkProxyPort?: number; // Override default NetworkProxy port for this domain } /** Port proxy settings including global allowed port ranges */ @@ -452,12 +456,14 @@ export class PortProxy { * @param socket - The incoming client socket * @param record - The connection record * @param initialData - Initial data chunk (TLS ClientHello) + * @param customProxyPort - Optional custom port for NetworkProxy (for domain-specific settings) */ private forwardToNetworkProxy( connectionId: string, socket: plugins.net.Socket, record: IConnectionRecord, - initialData: Buffer + initialData: Buffer, + customProxyPort?: number ): void { // Ensure NetworkProxy is initialized if (!this.networkProxy) { @@ -475,7 +481,8 @@ export class PortProxy { ); } - const proxyPort = this.networkProxy.getListeningPort(); + // Use the custom port if provided, otherwise use the default NetworkProxy port + const proxyPort = customProxyPort || this.networkProxy.getListeningPort(); const proxyHost = 'localhost'; // Assuming NetworkProxy runs locally if (this.settings.enableDetailedLogging) { @@ -1486,9 +1493,12 @@ export class PortProxy { ); } - // Check if this connection should be forwarded directly to NetworkProxy based on port - const shouldUseNetworkProxy = this.settings.useNetworkProxy && - this.settings.useNetworkProxy.includes(localPort); + // Check if this connection should be forwarded directly to NetworkProxy + // First check port-based forwarding settings + let shouldUseNetworkProxy = this.settings.useNetworkProxy && + this.settings.useNetworkProxy.includes(localPort); + + // We'll look for domain-specific settings after SNI extraction if (shouldUseNetworkProxy) { // For NetworkProxy ports, we want to capture the TLS handshake and forward directly @@ -1531,7 +1541,48 @@ export class PortProxy { if (SniHandler.isTlsHandshake(chunk)) { connectionRecord.isTLS = true; - // Forward directly to NetworkProxy without SNI processing + // Try to extract SNI for domain-specific NetworkProxy handling + const connInfo = { + sourceIp: remoteIP, + sourcePort: socket.remotePort || 0, + destIp: socket.localAddress || '', + destPort: socket.localPort || 0 + }; + + // Extract SNI to check for domain-specific NetworkProxy settings + const serverName = SniHandler.processTlsPacket( + chunk, + connInfo, + this.settings.enableTlsDebugLogging + ); + + if (serverName) { + // If we got an SNI, check for domain-specific NetworkProxy settings + const domainConfig = this.settings.domainConfigs.find((config) => + config.domains.some((d) => plugins.minimatch(serverName, d)) + ); + + // Save domain config and SNI in connection record + connectionRecord.domainConfig = domainConfig; + connectionRecord.lockedDomain = serverName; + + // Use domain-specific NetworkProxy port if configured + if (domainConfig?.useNetworkProxy) { + const networkProxyPort = domainConfig.networkProxyPort || this.settings.networkProxyPort; + + if (this.settings.enableDetailedLogging) { + console.log( + `[${connectionId}] Using domain-specific NetworkProxy for ${serverName} on port ${networkProxyPort}` + ); + } + + // Forward to NetworkProxy with domain-specific port + this.forwardToNetworkProxy(connectionId, socket, connectionRecord, chunk, networkProxyPort); + return; + } + } + + // Forward directly to NetworkProxy without domain-specific settings this.forwardToNetworkProxy(connectionId, socket, connectionRecord, chunk); } else { // If not TLS, use normal direct connection @@ -1657,6 +1708,29 @@ export class PortProxy { // Save domain config in connection record connectionRecord.domainConfig = domainConfig; + + // Check if this domain should use NetworkProxy (domain-specific setting) + if (domainConfig?.useNetworkProxy && this.networkProxy) { + if (this.settings.enableDetailedLogging) { + console.log( + `[${connectionId}] Domain ${serverName} is configured to use NetworkProxy` + ); + } + + const networkProxyPort = domainConfig.networkProxyPort || this.settings.networkProxyPort; + + if (initialChunk && connectionRecord.isTLS) { + // For TLS connections with initial chunk, forward to NetworkProxy + this.forwardToNetworkProxy( + connectionId, + socket, + connectionRecord, + initialChunk, + networkProxyPort // Pass the domain-specific NetworkProxy port if configured + ); + return; // Skip normal connection setup + } + } // IP validation is skipped if allowedIPs is empty if (domainConfig) {