Skip to content

Commit 47d1502

Browse files
committed
net,tls: fix session reuse with provided sockets
Preserve literal IP hosts on net.Socket before connection. This keeps wrapped TLS sessions bound to the correct peer when tls.connect() uses a provided socket. Fixes: #64402 Signed-off-by: harjoth <harjoth.khara@gmail.com>
1 parent 8fec65d commit 47d1502

2 files changed

Lines changed: 101 additions & 1 deletion

File tree

lib/net.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1566,6 +1566,8 @@ function lookupAndConnect(self, options) {
15661566

15671567
// If host is an IP, skip performing a lookup
15681568
const addressType = isIP(host);
1569+
// Retain the host before the IP fast path for TLS session identity binding.
1570+
self._host = host;
15691571
if (addressType) {
15701572
defaultTriggerAsyncIdScope(self[async_id_symbol], process.nextTick, () => {
15711573
if (self.connecting)
@@ -1596,7 +1598,6 @@ function lookupAndConnect(self, options) {
15961598

15971599
debug('connect: find host', host);
15981600
debug('connect: dns options', dnsopts);
1599-
self._host = host;
16001601
const lookup = options.lookup || dns.lookup;
16011602

16021603
if (dnsopts.family !== 4 && dnsopts.family !== 6 && !localAddress && autoSelectFamily) {
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Flags: --expose-internals
2+
'use strict';
3+
const common = require('../common');
4+
if (!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
const assert = require('assert');
8+
const fixtures = require('../common/fixtures');
9+
const { hasMultiLocalhost } = require('../common/net');
10+
const net = require('net');
11+
const tls = require('tls');
12+
const { once } = require('events');
13+
14+
async function connectWithSession(
15+
socket, session, maxVersion, expectedReuse = true, servername,
16+
) {
17+
const tlsSocket = tls.connect({
18+
socket,
19+
session,
20+
servername,
21+
maxVersion,
22+
rejectUnauthorized: false,
23+
});
24+
const close = once(tlsSocket, 'close');
25+
tlsSocket.resume();
26+
await once(tlsSocket, 'secureConnect');
27+
assert.strictEqual(tlsSocket.isSessionReused(), expectedReuse);
28+
await close;
29+
}
30+
31+
async function connectAndCaptureSession(
32+
port, maxVersion, host = '127.0.0.1', lookup,
33+
) {
34+
const socket = tls.connect({
35+
host,
36+
lookup,
37+
port,
38+
maxVersion,
39+
rejectUnauthorized: false,
40+
});
41+
const close = once(socket, 'close');
42+
const sessionPromise = once(socket, 'session').then(([session]) => session);
43+
socket.resume();
44+
await once(socket, 'secureConnect');
45+
assert.strictEqual(socket.isSessionReused(), false);
46+
const session = await sessionPromise;
47+
assert(Buffer.isBuffer(session));
48+
await close;
49+
return session;
50+
}
51+
52+
async function testVersion(maxVersion) {
53+
const server = tls.createServer({
54+
key: fixtures.readKey('agent1-key.pem'),
55+
cert: fixtures.readKey('agent1-cert.pem'),
56+
minVersion: maxVersion,
57+
maxVersion,
58+
}, (socket) => socket.end('ok'));
59+
60+
server.listen(0, '0.0.0.0');
61+
await once(server, 'listening');
62+
const { port } = server.address();
63+
const session = await connectAndCaptureSession(port, maxVersion);
64+
65+
let socket = net.connect({ host: '127.0.0.1', port });
66+
await once(socket, 'connect');
67+
await connectWithSession(socket, session, maxVersion);
68+
69+
socket = net.connect({ host: '127.0.0.1', port });
70+
await connectWithSession(socket, session, maxVersion);
71+
72+
if (hasMultiLocalhost()) {
73+
socket = net.connect({ host: '127.0.0.2', port });
74+
await connectWithSession(socket, session, maxVersion, false);
75+
}
76+
77+
const lookup = (_hostname, _options, callback) => {
78+
if (_options.all) {
79+
callback(null, [{ address: '127.0.0.1', family: 4 }]);
80+
} else {
81+
callback(null, '127.0.0.1', 4);
82+
}
83+
};
84+
const hostnameSession = await connectAndCaptureSession(
85+
port, maxVersion, 'localhost', lookup);
86+
socket = net.connect({ host: 'localhost', port, lookup });
87+
await connectWithSession(socket, hostnameSession, maxVersion);
88+
89+
socket = net.connect({ host: '127.0.0.1', port });
90+
await connectWithSession(socket, session, maxVersion, false, 'localhost');
91+
92+
server.close();
93+
await once(server, 'close');
94+
}
95+
96+
(async function() {
97+
await testVersion('TLSv1.2');
98+
await testVersion('TLSv1.3');
99+
})().then(common.mustCall());

0 commit comments

Comments
 (0)