feat(PortProxy): Add domain-specific NetworkProxy integration support to PortProxy

This commit is contained in:
Philipp Kunz 2025-03-11 17:50:56 +00:00
parent 1e89062167
commit 6fddafe9fd
3 changed files with 89 additions and 7 deletions

View File

@ -1,5 +1,13 @@
# Changelog # 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) ## 2025-03-11 - 3.38.2 - fix(core)
No code changes detected; bumping patch version for consistency. No code changes detected; bumping patch version for consistency.

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartproxy', 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.' 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.'
} }

View File

@ -11,6 +11,10 @@ export interface IDomainConfig {
portRanges?: Array<{ from: number; to: number }>; // Optional port ranges portRanges?: Array<{ from: number; to: number }>; // Optional port ranges
// Allow domain-specific timeout override // Allow domain-specific timeout override
connectionTimeout?: number; // Connection timeout override (ms) 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 */ /** Port proxy settings including global allowed port ranges */
@ -452,12 +456,14 @@ export class PortProxy {
* @param socket - The incoming client socket * @param socket - The incoming client socket
* @param record - The connection record * @param record - The connection record
* @param initialData - Initial data chunk (TLS ClientHello) * @param initialData - Initial data chunk (TLS ClientHello)
* @param customProxyPort - Optional custom port for NetworkProxy (for domain-specific settings)
*/ */
private forwardToNetworkProxy( private forwardToNetworkProxy(
connectionId: string, connectionId: string,
socket: plugins.net.Socket, socket: plugins.net.Socket,
record: IConnectionRecord, record: IConnectionRecord,
initialData: Buffer initialData: Buffer,
customProxyPort?: number
): void { ): void {
// Ensure NetworkProxy is initialized // Ensure NetworkProxy is initialized
if (!this.networkProxy) { 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 const proxyHost = 'localhost'; // Assuming NetworkProxy runs locally
if (this.settings.enableDetailedLogging) { if (this.settings.enableDetailedLogging) {
@ -1486,9 +1493,12 @@ export class PortProxy {
); );
} }
// Check if this connection should be forwarded directly to NetworkProxy based on port // Check if this connection should be forwarded directly to NetworkProxy
const shouldUseNetworkProxy = this.settings.useNetworkProxy && // First check port-based forwarding settings
this.settings.useNetworkProxy.includes(localPort); let shouldUseNetworkProxy = this.settings.useNetworkProxy &&
this.settings.useNetworkProxy.includes(localPort);
// We'll look for domain-specific settings after SNI extraction
if (shouldUseNetworkProxy) { if (shouldUseNetworkProxy) {
// For NetworkProxy ports, we want to capture the TLS handshake and forward directly // For NetworkProxy ports, we want to capture the TLS handshake and forward directly
@ -1531,7 +1541,48 @@ export class PortProxy {
if (SniHandler.isTlsHandshake(chunk)) { if (SniHandler.isTlsHandshake(chunk)) {
connectionRecord.isTLS = true; 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); this.forwardToNetworkProxy(connectionId, socket, connectionRecord, chunk);
} else { } else {
// If not TLS, use normal direct connection // If not TLS, use normal direct connection
@ -1657,6 +1708,29 @@ export class PortProxy {
// Save domain config in connection record // Save domain config in connection record
connectionRecord.domainConfig = domainConfig; 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 // IP validation is skipped if allowedIPs is empty
if (domainConfig) { if (domainConfig) {