fix(tls): Enforce strict SNI handling in TLS connections by terminating ClientHello messages lacking SNI when session tickets are disallowed and removing legacy session cache code.
This commit is contained in:
@ -172,35 +172,46 @@ export class ConnectionHandler {
|
||||
// Extract SNI for domain-specific NetworkProxy handling
|
||||
const serverName = this.tlsManager.extractSNI(chunk, connInfo);
|
||||
|
||||
if (serverName) {
|
||||
// If we got an SNI, check for domain-specific NetworkProxy settings
|
||||
const domainConfig = this.domainConfigManager.findDomainConfig(serverName);
|
||||
|
||||
// Save domain config and SNI in connection record
|
||||
record.domainConfig = domainConfig;
|
||||
record.lockedDomain = serverName;
|
||||
|
||||
// Use domain-specific NetworkProxy port if configured
|
||||
if (domainConfig && this.domainConfigManager.shouldUseNetworkProxy(domainConfig)) {
|
||||
const networkProxyPort = this.domainConfigManager.getNetworkProxyPort(domainConfig);
|
||||
|
||||
if (this.settings.enableDetailedLogging) {
|
||||
console.log(
|
||||
`[${connectionId}] Using domain-specific NetworkProxy for ${serverName} on port ${networkProxyPort}`
|
||||
);
|
||||
}
|
||||
|
||||
// Forward to NetworkProxy with domain-specific port
|
||||
this.networkProxyBridge.forwardToNetworkProxy(
|
||||
connectionId,
|
||||
socket,
|
||||
record,
|
||||
chunk,
|
||||
networkProxyPort,
|
||||
(reason) => this.connectionManager.initiateCleanupOnce(record, reason)
|
||||
);
|
||||
return;
|
||||
// If allowSessionTicket is false and we can't determine SNI, terminate the connection
|
||||
if (!serverName) {
|
||||
console.log(
|
||||
`[${connectionId}] No SNI detected in ClientHello and allowSessionTicket=false. ` +
|
||||
`Terminating connection to force new TLS handshake with SNI.`
|
||||
);
|
||||
if (record.incomingTerminationReason === null) {
|
||||
record.incomingTerminationReason = 'session_ticket_blocked_no_sni';
|
||||
this.connectionManager.incrementTerminationStat('incoming', 'session_ticket_blocked_no_sni');
|
||||
}
|
||||
socket.end();
|
||||
this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
|
||||
return;
|
||||
}
|
||||
|
||||
// Save domain config and SNI in connection record
|
||||
const domainConfig = this.domainConfigManager.findDomainConfig(serverName);
|
||||
record.domainConfig = domainConfig;
|
||||
record.lockedDomain = serverName;
|
||||
|
||||
// Use domain-specific NetworkProxy port if configured
|
||||
if (domainConfig && this.domainConfigManager.shouldUseNetworkProxy(domainConfig)) {
|
||||
const networkProxyPort = this.domainConfigManager.getNetworkProxyPort(domainConfig);
|
||||
|
||||
if (this.settings.enableDetailedLogging) {
|
||||
console.log(
|
||||
`[${connectionId}] Using domain-specific NetworkProxy for ${serverName} on port ${networkProxyPort}`
|
||||
);
|
||||
}
|
||||
|
||||
// Forward to NetworkProxy with domain-specific port
|
||||
this.networkProxyBridge.forwardToNetworkProxy(
|
||||
connectionId,
|
||||
socket,
|
||||
record,
|
||||
chunk,
|
||||
networkProxyPort,
|
||||
(reason) => this.connectionManager.initiateCleanupOnce(record, reason)
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -531,6 +542,39 @@ export class ConnectionHandler {
|
||||
|
||||
// Extract SNI
|
||||
serverName = this.tlsManager.extractSNI(chunk, connInfo) || '';
|
||||
|
||||
// If allowSessionTicket is false and this is a ClientHello with no SNI, terminate the connection
|
||||
if (this.settings.allowSessionTicket === false &&
|
||||
this.tlsManager.isClientHello(chunk) &&
|
||||
!serverName) {
|
||||
|
||||
// Check if this is a session resumption
|
||||
const resumptionInfo = this.tlsManager.handleSessionResumption(
|
||||
chunk,
|
||||
connectionId,
|
||||
false // No SNI
|
||||
);
|
||||
|
||||
if (resumptionInfo.shouldBlock) {
|
||||
console.log(
|
||||
`[${connectionId}] Session resumption without SNI detected and allowSessionTicket=false. ` +
|
||||
`Terminating connection to force new TLS handshake with SNI.`
|
||||
);
|
||||
if (record.incomingTerminationReason === null) {
|
||||
record.incomingTerminationReason = resumptionInfo.reason || 'session_ticket_blocked_no_sni';
|
||||
this.connectionManager.incrementTerminationStat(
|
||||
'incoming',
|
||||
resumptionInfo.reason || 'session_ticket_blocked_no_sni'
|
||||
);
|
||||
}
|
||||
socket.end();
|
||||
this.connectionManager.cleanupConnection(
|
||||
record,
|
||||
resumptionInfo.reason || 'session_ticket_blocked_no_sni'
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lock the connection to the negotiated SNI.
|
||||
|
Reference in New Issue
Block a user