fix(PortProxy): Improve TLS renegotiation SNI handling by first checking if the new SNI is allowed under the existing domain config. If not, attempt to find an alternative domain config and update the locked domain accordingly; otherwise, terminate the connection on SNI mismatch.
This commit is contained in:
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@push.rocks/smartproxy',
|
||||
version: '3.30.6',
|
||||
version: '3.30.7',
|
||||
description: 'A powerful proxy package that effectively handles high traffic, with features such as SSL/TLS support, port proxying, WebSocket handling, and dynamic routing with authentication options.'
|
||||
}
|
||||
|
@@ -873,45 +873,73 @@ export class PortProxy {
|
||||
|
||||
// Check if the SNI has changed
|
||||
if (newSNI && newSNI !== record.lockedDomain) {
|
||||
// Instead of immediately terminating, check if the new SNI would be allowed
|
||||
// by the same ruleset that allowed the initial connection
|
||||
const newDomainConfig = this.settings.domainConfigs.find((config) =>
|
||||
config.domains.some((d) => plugins.minimatch(newSNI, d))
|
||||
);
|
||||
// Always check whether the new SNI would be allowed by the EXISTING domain config first
|
||||
// This ensures we're using the same ruleset that allowed the initial connection
|
||||
let allowed = false;
|
||||
|
||||
// If we found a matching domain config, check IP rules
|
||||
if (newDomainConfig) {
|
||||
const effectiveAllowedIPs = [
|
||||
...newDomainConfig.allowedIPs,
|
||||
...(this.settings.defaultAllowedIPs || []),
|
||||
];
|
||||
const effectiveBlockedIPs = [
|
||||
...(newDomainConfig.blockedIPs || []),
|
||||
...(this.settings.defaultBlockedIPs || []),
|
||||
];
|
||||
// First check if the exact original domain config would allow this new SNI
|
||||
if (record.domainConfig) {
|
||||
// Check if the new SNI matches any domain pattern in the original domain config
|
||||
allowed = record.domainConfig.domains.some(d => plugins.minimatch(newSNI, d));
|
||||
|
||||
// Check if the IP is allowed for the new domain
|
||||
if (isGlobIPAllowed(record.remoteIP, effectiveAllowedIPs, effectiveBlockedIPs)) {
|
||||
// Allow the domain switch - Chrome is reusing the connection for a different domain
|
||||
if (this.settings.enableDetailedLogging) {
|
||||
console.log(
|
||||
`[${connectionId}] Rehandshake with new SNI: ${newSNI} (previously ${record.lockedDomain}). ` +
|
||||
`New domain is allowed by rules, permitting connection reuse.`
|
||||
);
|
||||
}
|
||||
|
||||
// Update the locked domain to the new domain
|
||||
record.lockedDomain = newSNI;
|
||||
return;
|
||||
if (allowed && this.settings.enableDetailedLogging) {
|
||||
console.log(
|
||||
`[${connectionId}] Rehandshake with new SNI: ${newSNI} matched existing domain config ` +
|
||||
`patterns ${record.domainConfig.domains.join(', ')}. Allowing connection reuse.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, either no matching domain config was found or the IP is not allowed
|
||||
console.log(
|
||||
`[${connectionId}] Rehandshake detected with different SNI: ${newSNI} vs locked ${record.lockedDomain}. ` +
|
||||
`New domain not allowed by rules. Terminating connection.`
|
||||
);
|
||||
this.initiateCleanupOnce(record, 'sni_mismatch');
|
||||
// If not allowed by the existing domain config, try to find another domain config
|
||||
if (!allowed) {
|
||||
const newDomainConfig = this.settings.domainConfigs.find((config) =>
|
||||
config.domains.some((d) => plugins.minimatch(newSNI, d))
|
||||
);
|
||||
|
||||
// If we found a matching domain config, check IP rules
|
||||
if (newDomainConfig) {
|
||||
const effectiveAllowedIPs = [
|
||||
...newDomainConfig.allowedIPs,
|
||||
...(this.settings.defaultAllowedIPs || []),
|
||||
];
|
||||
const effectiveBlockedIPs = [
|
||||
...(newDomainConfig.blockedIPs || []),
|
||||
...(this.settings.defaultBlockedIPs || []),
|
||||
];
|
||||
|
||||
// Check if the IP is allowed for the new domain
|
||||
allowed = isGlobIPAllowed(record.remoteIP, effectiveAllowedIPs, effectiveBlockedIPs);
|
||||
|
||||
if (allowed && this.settings.enableDetailedLogging) {
|
||||
console.log(
|
||||
`[${connectionId}] Rehandshake with new SNI: ${newSNI} (previously ${record.lockedDomain}). ` +
|
||||
`New domain is allowed by different domain config rules, permitting connection reuse.`
|
||||
);
|
||||
}
|
||||
|
||||
// Update the domain config reference to the new one
|
||||
if (allowed) {
|
||||
record.domainConfig = newDomainConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowed) {
|
||||
// Update the locked domain to the new domain
|
||||
record.lockedDomain = newSNI;
|
||||
if (this.settings.enableDetailedLogging) {
|
||||
console.log(
|
||||
`[${connectionId}] Updated locked domain for connection from ${record.remoteIP} to: ${newSNI}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// If we get here, either no matching domain config was found or the IP is not allowed
|
||||
console.log(
|
||||
`[${connectionId}] Rehandshake detected with different SNI: ${newSNI} vs locked ${record.lockedDomain}. ` +
|
||||
`New domain not allowed by any rules. Terminating connection.`
|
||||
);
|
||||
this.initiateCleanupOnce(record, 'sni_mismatch');
|
||||
}
|
||||
} else if (newSNI && this.settings.enableDetailedLogging) {
|
||||
console.log(
|
||||
`[${connectionId}] Rehandshake detected with same SNI: ${newSNI}. Allowing.`
|
||||
|
Reference in New Issue
Block a user