Compare commits

...

4 Commits

Author SHA1 Message Date
794e1292e5 4.1.3
Some checks failed
Default (tags) / security (push) Successful in 38s
Default (tags) / test (push) Failing after 1m0s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-15 18:51:50 +00:00
ee79f9ab7c fix(connectionhandler): Improve handling of TLS ClientHello messages when allowSessionTicket is disabled and no SNI is provided by sending a warning alert (unrecognized_name, code 0x70) with a proper callback and delay to ensure the alert is transmitted before closing the connection. 2025-03-15 18:51:50 +00:00
107bc3b50b 4.1.2
Some checks failed
Default (tags) / security (push) Successful in 30s
Default (tags) / test (push) Failing after 1m2s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-03-15 17:16:18 +00:00
97982976c8 fix(connectionhandler): Send proper TLS alert before terminating connections when SNI is missing and session tickets are disallowed. 2025-03-15 17:16:18 +00:00
4 changed files with 93 additions and 26 deletions

View File

@ -1,5 +1,19 @@
# Changelog
## 2025-03-15 - 4.1.3 - fix(connectionhandler)
Improve handling of TLS ClientHello messages when allowSessionTicket is disabled and no SNI is provided by sending a warning alert (unrecognized_name, code 0x70) with a proper callback and delay to ensure the alert is transmitted before closing the connection.
- Replace the fatal alert (0x02/0x40) with a warning alert (0x01/0x70) to notify clients to send SNI.
- Use socket.write callback to wait 100ms after sending the alert before terminating the connection.
- Remove the previous short (50ms) delay in favor of a more reliable delay mechanism before cleanup.
## 2025-03-15 - 4.1.2 - fix(connectionhandler)
Send proper TLS alert before terminating connections when SNI is missing and session tickets are disallowed.
- Added logic to transmit a fatal TLS alert (Handshake Failure) before closing the connection when no SNI is present with allowSessionTicket=false.
- Introduced a slight 50ms delay after sending the alert to ensure the client receives the alert properly.
- Applied these changes both for the initial ClientHello and when handling subsequent TLS data.
## 2025-03-15 - 4.1.1 - 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.

View File

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

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartproxy',
version: '4.1.1',
version: '4.1.3',
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

@ -174,16 +174,50 @@ export class ConnectionHandler {
// If allowSessionTicket is false and we can't determine SNI, terminate the connection
if (!serverName) {
// Always block when allowSessionTicket is false and there's no SNI
console.log(
`[${connectionId}] No SNI detected in ClientHello and allowSessionTicket=false. ` +
`Terminating connection to force new TLS handshake with SNI.`
);
// Send a proper TLS alert before ending the connection
// Using "unrecognized_name" (112) alert which is a warning level alert (1)
// that encourages clients to retry with proper SNI
const alertData = Buffer.from([
0x15, // Alert record type
0x03, 0x03, // TLS 1.2 version
0x00, 0x02, // Length
0x01, // Warning alert level (not fatal)
0x70 // unrecognized_name alert (code 112)
]);
try {
socket.write(alertData, () => {
// Only close the socket after we're sure the alert was sent
// Give the alert time to be processed by the client
setTimeout(() => {
socket.end();
// Ensure complete cleanup happens a bit later
setTimeout(() => {
if (!socket.destroyed) {
socket.destroy();
}
this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
}, 100);
}, 100);
});
} catch (err) {
// If we can't send the alert, fall back to immediate termination
socket.end();
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');
}
socket.end();
this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
return;
}
@ -548,32 +582,51 @@ export class ConnectionHandler {
this.tlsManager.isClientHello(chunk) &&
!serverName) {
// Check if this is a session resumption
const resumptionInfo = this.tlsManager.handleSessionResumption(
chunk,
connectionId,
false // No SNI
// Always block ClientHello without SNI when allowSessionTicket is false
console.log(
`[${connectionId}] No SNI detected in ClientHello and allowSessionTicket=false. ` +
`Terminating connection to force new TLS handshake with 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'
);
}
// Send a proper TLS alert before ending the connection
// Using "unrecognized_name" (112) alert which is a warning level alert (1)
// that encourages clients to retry with proper SNI
const alertData = Buffer.from([
0x15, // Alert record type
0x03, 0x03, // TLS 1.2 version
0x00, 0x02, // Length
0x01, // Warning alert level (not fatal)
0x70 // unrecognized_name alert (code 112)
]);
try {
socket.write(alertData, () => {
// Only close the socket after we're sure the alert was sent
// Give the alert time to be processed by the client
setTimeout(() => {
socket.end();
// Ensure complete cleanup happens a bit later
setTimeout(() => {
if (!socket.destroyed) {
socket.destroy();
}
this.connectionManager.cleanupConnection(record, 'session_ticket_blocked_no_sni');
}, 100);
}, 100);
});
} catch (err) {
// If we can't send the alert, fall back to immediate termination
socket.end();
this.connectionManager.cleanupConnection(
record,
resumptionInfo.reason || 'session_ticket_blocked_no_sni'
);
return;
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;
}
}