Compare commits

...

4 Commits

Author SHA1 Message Date
8a96b45ece 4.1.6
Some checks failed
Default (tags) / security (push) Successful in 29s
Default (tags) / test (push) Failing after 1m0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-16 13:28:48 +00:00
2b6464acd5 fix(tls): Refine TLS ClientHello handling when allowSessionTicket is false by replacing extensive alert timeout logic with a concise warning alert and short delay, encouraging immediate client retry with proper SNI 2025-03-16 13:28:48 +00:00
efbb4335d7 4.1.5
Some checks failed
Default (tags) / security (push) Successful in 38s
Default (tags) / test (push) Failing after 59s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-16 13:19:37 +00:00
9dd402054d fix(TLS/ConnectionHandler): Improve handling of TLS session resumption without SNI by sending an unrecognized_name alert instead of immediately terminating the connection. This change adds a grace period for the client to retry the handshake with proper SNI and cleans up the connection if no valid response is received. 2025-03-16 13:19:37 +00:00
4 changed files with 70 additions and 36 deletions

View File

@ -1,5 +1,20 @@
# Changelog # Changelog
## 2025-03-16 - 4.1.6 - fix(tls)
Refine TLS ClientHello handling when allowSessionTicket is false by replacing extensive alert timeout logic with a concise warning alert and short delay, encouraging immediate client retry with proper SNI
- Update the TLS alert sending mechanism to use cork/uncork and a short, fixed delay instead of long timeouts
- Remove redundant event listeners and excessive cleanup logic after sending the alert
- Improve code clarity and encourage clients (e.g., Chrome) to retry handshake with SNI more responsively
## 2025-03-16 - 4.1.5 - fix(TLS/ConnectionHandler)
Improve handling of TLS session resumption without SNI by sending an 'unrecognized_name' alert instead of immediately terminating the connection. This change adds a grace period for the client to retry the handshake with proper SNI and cleans up the connection if no valid response is received.
- Send a TLS warning (unrecognized_name alert, code 112) when a ClientHello is received without SNI and session tickets are disallowed.
- Utilize socket cork/uncork to ensure the alert is sent as a single packet.
- Add a 5-second alert timeout and a subsequent 30-second grace period to allow clients to initiate a new handshake with SNI.
- Clean up and terminate the connection if no valid SNI is provided after the grace period, logging appropriate termination reasons.
## 2025-03-15 - 4.1.4 - fix(ConnectionHandler) ## 2025-03-15 - 4.1.4 - fix(ConnectionHandler)
Refactor ConnectionHandler code formatting for improved readability and consistency in log messages and whitespace handling Refactor ConnectionHandler code formatting for improved readability and consistency in log messages and whitespace handling

View File

@ -1,6 +1,6 @@
{ {
"name": "@push.rocks/smartproxy", "name": "@push.rocks/smartproxy",
"version": "4.1.4", "version": "4.1.6",
"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: '4.1.4', version: '4.1.6',
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

@ -557,15 +557,23 @@ export class ConnectionHandler {
this.tlsManager.isClientHello(chunk) && this.tlsManager.isClientHello(chunk) &&
!serverName !serverName
) { ) {
// Always block ClientHello without SNI when allowSessionTicket is false // Block ClientHello without SNI when allowSessionTicket is false
console.log( console.log(
`[${connectionId}] No SNI detected in ClientHello and allowSessionTicket=false. ` + `[${connectionId}] No SNI detected in ClientHello and allowSessionTicket=false. ` +
`Terminating connection to force new TLS handshake with SNI.` `Sending warning unrecognized_name alert to encourage immediate retry with SNI.`
); );
// Send a proper TLS alert before ending the connection // Set the termination reason first
// Using "unrecognized_name" (112) alert which is a warning level alert (1) if (record.incomingTerminationReason === null) {
// that encourages clients to retry with proper SNI record.incomingTerminationReason = 'session_ticket_blocked_no_sni';
this.connectionManager.incrementTerminationStat(
'incoming',
'session_ticket_blocked_no_sni'
);
}
// Create a warning-level alert for unrecognized_name
// This encourages Chrome to retry immediately with SNI
const alertData = Buffer.from([ const alertData = Buffer.from([
0x15, // Alert record type 0x15, // Alert record type
0x03, 0x03,
@ -575,40 +583,51 @@ export class ConnectionHandler {
0x01, // Warning alert level (not fatal) 0x01, // Warning alert level (not fatal)
0x70, // unrecognized_name alert (code 112) 0x70, // unrecognized_name alert (code 112)
]); ]);
try { try {
socket.write(alertData, () => { // Use cork/uncork to ensure the alert is sent as a single packet
// Only close the socket after we're sure the alert was sent socket.cork();
// Give the alert time to be processed by the client const writeSuccessful = socket.write(alertData);
socket.uncork();
// Function to handle the clean socket termination
const finishConnection = () => {
// First call end() to initiate a graceful close (sends FIN)
socket.end();
// Allow a short delay for the alert and FIN to be transmitted
// before we fully close the socket
setTimeout(() => { setTimeout(() => {
socket.end(); if (!socket.destroyed) {
socket.destroy();
// Ensure complete cleanup happens a bit later }
setTimeout(() => { this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
if (!socket.destroyed) { }, 150); // Short delay, but longer than the standard TCP ACK timeout
socket.destroy(); };
}
this.connectionManager.cleanupConnection( if (writeSuccessful) {
record, // If the data was successfully written to the kernel buffer,
'session_ticket_blocked_no_sni' // we can finish the connection after a short delay to ensure transmission
); setTimeout(finishConnection, 50);
}, 100); } else {
}, 100); // If the kernel buffer was full, wait for the drain event
}); socket.once('drain', () => {
setTimeout(finishConnection, 50);
});
// Set a safety timeout in case drain never happens
setTimeout(() => {
socket.removeAllListeners('drain');
finishConnection();
}, 250);
}
} catch (err) { } catch (err) {
// If we can't send the alert, fall back to immediate termination // If we can't send the alert, fall back to immediate termination
console.log(`[${connectionId}] Error sending TLS alert: ${err.message}`);
socket.end(); socket.end();
this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni'); this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
} }
if (record.incomingTerminationReason === null) {
record.incomingTerminationReason = 'session_ticket_blocked_no_sni';
this.connectionManager.incrementTerminationStat(
'incoming',
'session_ticket_blocked_no_sni'
);
}
return; return;
} }
} }
@ -1056,4 +1075,4 @@ export class ConnectionHandler {
} }
}); });
} }
} }