Skip to content

Commit 01445e8

Browse files
committed
extract magic number into constant and make use of cert we have
1 parent 8e35f8e commit 01445e8

2 files changed

Lines changed: 48 additions & 47 deletions

File tree

src/cmap/connect.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,15 @@ export async function prepareHandshakeDocument(
281281
return handshakeDoc;
282282
}
283283

284+
/**
285+
* @internal
286+
* Default TCP keepAlive initial delay in milliseconds.
287+
* Set to half the Azure load balancer idle timeout (240s) to ensure
288+
* probes fire well before cloud LBs (Azure, AWS PrivateLink/NLB)
289+
* drop idle connections.
290+
* */
291+
export const DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS = 120_000;
292+
284293
/** @public */
285294
export const LEGAL_TLS_SOCKET_OPTIONS = [
286295
'allowPartialTrustChain',
@@ -324,7 +333,7 @@ function parseConnectOptions(options: ConnectionOptions): SocketConnectOpts {
324333
(result as Document)[name] = options[name];
325334
}
326335
}
327-
result.keepAliveInitialDelay ??= 120000;
336+
result.keepAliveInitialDelay ??= DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS;
328337
result.keepAlive = true;
329338
result.noDelay = options.noDelay ?? true;
330339

@@ -370,6 +379,9 @@ export async function makeSocket(options: MakeConnectionOptions): Promise<Stream
370379
const useTLS = options.tls ?? false;
371380
const connectTimeoutMS = options.connectTimeoutMS ?? 30000;
372381
const existingSocket = options.existingSocket;
382+
const keepAliveInitialDelay =
383+
options.keepAliveInitialDelay ?? DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS;
384+
const noDelay = options.noDelay ?? true;
373385

374386
let socket: Stream;
375387

@@ -396,8 +408,11 @@ export async function makeSocket(options: MakeConnectionOptions): Promise<Stream
396408
socket = net.createConnection(parseConnectOptions(options));
397409
}
398410

399-
socket.setKeepAlive(true, options.keepAliveInitialDelay ?? 120_000);
400-
socket.setNoDelay(options.noDelay ?? true);
411+
// Explicit setKeepAlive/setNoDelay are required because tls.connect() silently
412+
// ignores these constructor options due to a Node.js bug.
413+
// See: https://github.com/nodejs/node/issues/62003
414+
socket.setKeepAlive(true, keepAliveInitialDelay);
415+
socket.setNoDelay(noDelay);
401416
socket.setTimeout(connectTimeoutMS);
402417

403418
let cancellationHandler: ((err: Error) => void) | null = null;

test/unit/cmap/connect.test.ts

Lines changed: 30 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect } from 'chai';
2-
import { execSync } from 'child_process';
3-
import * as crypto from 'crypto';
2+
import * as fs from 'fs';
43
import * as net from 'net';
4+
import * as path from 'path';
55
import * as process from 'process';
66
import * as sinon from 'sinon';
77
import * as tls from 'tls';
@@ -12,6 +12,7 @@ import {
1212
connect,
1313
type Connection,
1414
type ConnectionOptions,
15+
DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS,
1516
HostAddress,
1617
isHello,
1718
LEGACY_HELLO_COMMAND,
@@ -456,27 +457,24 @@ describe('Connect Tests', function () {
456457
});
457458

458459
describe('makeSocket', function () {
459-
// TLS sockets created by tls.connect() do not honor keepAlive/noDelay constructor
460-
// options due to a Node.js bug (options are not forwarded to the net.Socket constructor).
461-
// The driver must call setKeepAlive/setNoDelay explicitly on all sockets.
462-
// See: https://github.com/nodejs/node/issues/...
463-
464460
let tlsServer: tls.Server;
465461
let tlsPort: number;
466462
let setKeepAliveSpy: sinon.SinonSpy;
467463
let setNoDelaySpy: sinon.SinonSpy;
468464

465+
const serverPem = fs.readFileSync(
466+
path.join(__dirname, '../../integration/auth/ssl/server.pem')
467+
);
468+
469469
before(function (done) {
470-
const { privateKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 2048 });
471-
const key = privateKey.export({ type: 'pkcs8', format: 'pem' });
472-
const cert = execSync(
473-
'openssl req -new -x509 -key /dev/stdin -out /dev/stdout -days 1 -subj /CN=localhost -batch 2>/dev/null',
474-
{ input: key }
475-
).toString();
476-
477-
tlsServer = tls.createServer({ key, cert }, () => {
478-
/* empty */
479-
});
470+
// @SECLEVEL=0 allows the legacy test certificate (signed with SHA-1/1024-bit RSA)
471+
// to be accepted by OpenSSL 3.x, which rejects at the default security level.
472+
tlsServer = tls.createServer(
473+
{ key: serverPem, cert: serverPem, ciphers: 'DEFAULT:@SECLEVEL=0' },
474+
() => {
475+
/* empty */
476+
}
477+
);
480478
tlsServer.listen(0, '127.0.0.1', () => {
481479
tlsPort = (tlsServer.address() as net.AddressInfo).port;
482480
done();
@@ -501,43 +499,37 @@ describe('Connect Tests', function () {
501499
const socket = await makeSocket({
502500
hostAddress: new HostAddress(`127.0.0.1:${tlsPort}`),
503501
tls: true,
504-
rejectUnauthorized: false
502+
rejectUnauthorized: false,
503+
ciphers: 'DEFAULT:@SECLEVEL=0'
505504
} as ConnectionOptions);
505+
socket.destroy();
506506

507-
try {
508-
expect(setKeepAliveSpy).to.have.been.calledWith(true, 120000);
509-
} finally {
510-
socket.destroy();
511-
}
507+
expect(setKeepAliveSpy).to.have.been.calledWith(true, DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS);
512508
});
513509

514510
it('calls setKeepAlive with custom keepAliveInitialDelay', async function () {
515511
const socket = await makeSocket({
516512
hostAddress: new HostAddress(`127.0.0.1:${tlsPort}`),
517513
tls: true,
518514
rejectUnauthorized: false,
515+
ciphers: 'DEFAULT:@SECLEVEL=0',
519516
keepAliveInitialDelay: 5000
520517
} as ConnectionOptions);
518+
socket.destroy();
521519

522-
try {
523-
expect(setKeepAliveSpy).to.have.been.calledWith(true, 5000);
524-
} finally {
525-
socket.destroy();
526-
}
520+
expect(setKeepAliveSpy).to.have.been.calledWith(true, 5000);
527521
});
528522

529523
it('calls setNoDelay with true by default', async function () {
530524
const socket = await makeSocket({
531525
hostAddress: new HostAddress(`127.0.0.1:${tlsPort}`),
532526
tls: true,
533-
rejectUnauthorized: false
527+
rejectUnauthorized: false,
528+
ciphers: 'DEFAULT:@SECLEVEL=0'
534529
} as ConnectionOptions);
530+
socket.destroy();
535531

536-
try {
537-
expect(setNoDelaySpy).to.have.been.calledWith(true);
538-
} finally {
539-
socket.destroy();
540-
}
532+
expect(setNoDelaySpy).to.have.been.calledWith(true);
541533
});
542534
});
543535

@@ -547,25 +539,19 @@ describe('Connect Tests', function () {
547539
hostAddress: new HostAddress(`127.0.0.1:${tlsPort}`),
548540
tls: false
549541
} as ConnectionOptions);
542+
socket.destroy();
550543

551-
try {
552-
expect(setKeepAliveSpy).to.have.been.calledWith(true, 120000);
553-
} finally {
554-
socket.destroy();
555-
}
544+
expect(setKeepAliveSpy).to.have.been.calledWith(true, DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS);
556545
});
557546

558547
it('calls setNoDelay with true by default', async function () {
559548
const socket = await makeSocket({
560549
hostAddress: new HostAddress(`127.0.0.1:${tlsPort}`),
561550
tls: false
562551
} as ConnectionOptions);
552+
socket.destroy();
563553

564-
try {
565-
expect(setNoDelaySpy).to.have.been.calledWith(true);
566-
} finally {
567-
socket.destroy();
568-
}
554+
expect(setNoDelaySpy).to.have.been.calledWith(true);
569555
});
570556
});
571557
});

0 commit comments

Comments
 (0)