Compare commits

..

6 Commits

Author SHA1 Message Date
8196de4fa3 3.39.0
Some checks failed
Default (tags) / security (push) Successful in 35s
Default (tags) / test (push) Failing after 1m2s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 17:50:57 +00:00
6fddafe9fd feat(PortProxy): Add domain-specific NetworkProxy integration support to PortProxy 2025-03-11 17:50:56 +00:00
1e89062167 3.38.2
Some checks failed
Default (tags) / security (push) Successful in 22s
Default (tags) / test (push) Failing after 1m11s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 17:38:32 +00:00
21a24fd95b fix(core): No code changes detected; bumping patch version for consistency. 2025-03-11 17:38:32 +00:00
03ef5e7f6e 3.38.1
Some checks failed
Default (tags) / security (push) Successful in 21s
Default (tags) / test (push) Failing after 1m1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-11 17:37:43 +00:00
415b82a84a fix(PortProxy): Improve SNI extraction handling in PortProxy by passing explicit connection info to extractSNIWithResumptionSupport for better TLS renegotiation and debug logging. 2025-03-11 17:37:43 +00:00
4 changed files with 134 additions and 11 deletions

View File

@ -1,5 +1,24 @@
# 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)
No code changes detected; bumping patch version for consistency.
## 2025-03-11 - 3.38.1 - fix(PortProxy)
Improve SNI extraction handling in PortProxy by passing explicit connection info to extractSNIWithResumptionSupport for better TLS renegotiation and debug logging.
- In the renegotiation handler, create and pass a connection info object (sourceIp, sourcePort, destIp, destPort) instead of a boolean flag.
- Update the TLS handshake processing to construct a connection info object for detailed SNI extraction and logging.
- Enhance consistency by using processTlsPacket with cached SNI hints during fallback.
## 2025-03-11 - 3.38.0 - feat(SniHandler) ## 2025-03-11 - 3.38.0 - feat(SniHandler)
Enhance SNI extraction to support fragmented ClientHello messages, TLS 1.3 early data, and improved PSK parsing Enhance SNI extraction to support fragmented ClientHello messages, TLS 1.3 early data, and improved PSK parsing

View File

@ -1,6 +1,6 @@
{ {
"name": "@push.rocks/smartproxy", "name": "@push.rocks/smartproxy",
"version": "3.38.0", "version": "3.39.0",
"private": false, "private": false,
"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.",
"main": "dist_ts/index.js", "main": "dist_ts/index.js",

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartproxy', name: '@push.rocks/smartproxy',
version: '3.38.0', 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) {
@ -920,7 +927,15 @@ export class PortProxy {
if (SniHandler.isClientHello(renegChunk)) { if (SniHandler.isClientHello(renegChunk)) {
try { try {
// Extract SNI from ClientHello // Extract SNI from ClientHello
const newSNI = SniHandler.extractSNIWithResumptionSupport(renegChunk, this.settings.enableTlsDebugLogging); // Create a connection info object for the existing connection
const connInfo = {
sourceIp: record.remoteIP,
sourcePort: record.incoming.remotePort || 0,
destIp: record.incoming.localAddress || '',
destPort: record.incoming.localPort || 0
};
const newSNI = SniHandler.extractSNIWithResumptionSupport(renegChunk, connInfo, this.settings.enableTlsDebugLogging);
// Skip if no SNI was found // Skip if no SNI was found
if (!newSNI) return; if (!newSNI) return;
@ -1478,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
@ -1523,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
@ -1590,7 +1649,15 @@ export class PortProxy {
`[${connectionId}] TLS handshake detected from ${remoteIP}, ${chunk.length} bytes` `[${connectionId}] TLS handshake detected from ${remoteIP}, ${chunk.length} bytes`
); );
// Try to extract SNI and log detailed debug info // Try to extract SNI and log detailed debug info
SniHandler.extractSNIWithResumptionSupport(chunk, true); // Create connection info for debug logging
const debugConnInfo = {
sourceIp: remoteIP,
sourcePort: socket.remotePort || 0,
destIp: socket.localAddress || '',
destPort: socket.localPort || 0
};
SniHandler.extractSNIWithResumptionSupport(chunk, debugConnInfo, true);
} }
} }
}); });
@ -1641,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) {
@ -1797,7 +1887,21 @@ export class PortProxy {
); );
} }
serverName = SniHandler.extractSNIWithResumptionSupport(chunk, this.settings.enableTlsDebugLogging) || ''; // Create connection info object for SNI extraction
const connInfo = {
sourceIp: remoteIP,
sourcePort: socket.remotePort || 0,
destIp: socket.localAddress || '',
destPort: socket.localPort || 0
};
// Use the new processTlsPacket method for comprehensive handling
serverName = SniHandler.processTlsPacket(
chunk,
connInfo,
this.settings.enableTlsDebugLogging,
connectionRecord.lockedDomain // Pass any previously negotiated domain as a hint
) || '';
} }
// Lock the connection to the negotiated SNI. // Lock the connection to the negotiated SNI.