fix(smartproxy): Enhance SSL/TLS handling with SNI and error logging

This commit is contained in:
Philipp Kunz 2025-02-21 18:47:18 +00:00
parent 63e1cd48e8
commit 58bd6b4a85
3 changed files with 90 additions and 54 deletions

View File

@ -1,5 +1,12 @@
# Changelog # Changelog
## 2025-02-21 - 3.4.2 - fix(smartproxy)
Enhance SSL/TLS handling with SNI and error logging
- Improved handling for SNI-enabled and non-SNI connections
- Added detailed logging for connection establishment and rejections
- Introduced error logging for TLS client errors and server errors
## 2025-02-21 - 3.4.1 - fix(PortProxy) ## 2025-02-21 - 3.4.1 - fix(PortProxy)
Normalize IP addresses for port proxy to handle IPv4-mapped IPv6 addresses. Normalize IP addresses for port proxy to handle IPv4-mapped IPv6 addresses.

View File

@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@push.rocks/smartproxy', name: '@push.rocks/smartproxy',
version: '3.4.1', version: '3.4.2',
description: 'a proxy for handling high workloads of proxying' description: 'a proxy for handling high workloads of proxying'
} }

View File

@ -67,19 +67,40 @@ export class PortProxy {
}; };
const server = this.settings.sniEnabled const server = this.settings.sniEnabled
? plugins.tls.createServer(this.settings) ? plugins.tls.createServer({
...this.settings,
SNICallback: (serverName: string, cb: (err: Error | null, ctx?: plugins.tls.SecureContext) => void) => {
console.log(`SNI request for domain: ${serverName}`);
const domainConfig = findMatchingDomain(serverName);
if (!domainConfig) {
console.log(`SNI rejected: No matching domain config for ${serverName}`);
cb(new Error(`No configuration for domain: ${serverName}`));
return;
}
// Create context with the provided TLS settings
const ctx = plugins.tls.createSecureContext(this.settings);
cb(null, ctx);
}
})
: plugins.net.createServer(); : plugins.net.createServer();
this.netServer = server.on('connection', (from: plugins.net.Socket) => { const handleConnection = (from: plugins.net.Socket | plugins.tls.TLSSocket) => {
const remoteIP = from.remoteAddress || ''; const remoteIP = from.remoteAddress || '';
let serverName = '';
if (this.settings.sniEnabled && from instanceof plugins.tls.TLSSocket) { if (this.settings.sniEnabled && from instanceof plugins.tls.TLSSocket) {
const serverName = (from as any).servername || ''; serverName = (from as any).servername || '';
const domainConfig = findMatchingDomain(serverName); console.log(`TLS Connection from ${remoteIP} for domain: ${serverName}`);
}
// For TLS connections, we've already validated the domain in SNICallback
if (!this.settings.sniEnabled || from instanceof plugins.tls.TLSSocket) {
const domainConfig = serverName ? findMatchingDomain(serverName) : undefined;
if (!domainConfig) { if (!domainConfig) {
// If no matching domain config found, check default IPs if available // If no matching domain config found, check default IPs if available
if (!this.settings.defaultAllowedIPs || !isAllowed(remoteIP, this.settings.defaultAllowedIPs)) { if (!this.settings.defaultAllowedIPs || !isAllowed(remoteIP, this.settings.defaultAllowedIPs)) {
console.log(`Connection rejected: No matching domain config for ${serverName} from IP ${remoteIP}`); console.log(`Connection rejected: No matching domain config for ${serverName || 'non-SNI'} from IP ${remoteIP}`);
from.end(); from.end();
return; return;
} }
@ -101,7 +122,7 @@ export class PortProxy {
host: this.settings.toHost!, host: this.settings.toHost!,
port: this.settings.toPort, port: this.settings.toPort,
}); });
console.log(`Connection established: ${remoteIP} -> ${this.settings.toHost}:${this.settings.toPort}${this.settings.sniEnabled ? ` (SNI: ${(from as any).servername || 'none'})` : ''}`); console.log(`Connection established: ${remoteIP} -> ${this.settings.toHost}:${this.settings.toPort}${serverName ? ` (SNI: ${serverName})` : ''}`);
from.setTimeout(120000); from.setTimeout(120000);
from.pipe(to); from.pipe(to);
to.pipe(from); to.pipe(from);
@ -129,9 +150,17 @@ export class PortProxy {
to.on('end', () => { to.on('end', () => {
cleanUpSockets(from, to); cleanUpSockets(from, to);
}); });
this.netServer = server
.on('connection', handleConnection)
.on('secureConnection', handleConnection)
.on('tlsClientError', (err, tlsSocket) => {
console.log(`TLS Client Error: ${err.message}`);
})
.on('error', (err) => {
console.log(`Server Error: ${err.message}`);
}) })
.listen(this.settings.fromPort); .listen(this.settings.fromPort);
console.log(`PortProxy -> OK: Now listening on port ${this.settings.fromPort}`); console.log(`PortProxy -> OK: Now listening on port ${this.settings.fromPort}${this.settings.sniEnabled ? ' (SNI enabled)' : ''}`);
} }
public async stop() { public async stop() {