Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions doc/api/tls.md
Original file line number Diff line number Diff line change
Expand Up @@ -1668,6 +1668,27 @@ and their processing can be delayed due to packet loss or reordering. However,
smaller fragments add extra TLS framing bytes and CPU overhead, which may
decrease overall server throughput.

### `tlsSocket.socket`

<!-- YAML
added: REPLACEME
-->

* Type: {net.Socket|stream.Duplex|null}

The underlying socket or stream that this socket reads and writes TLS data
through. This is the `socket` passed to [`new tls.TLSSocket()`][] or
[`tls.connect()`][], or the connection given to a [`tls.Server`][] by its
`'connection'` event.

This is only `null` for client sockets that manage their own connection,
created by [`tls.connect()`][] with a `port` or `path` rather than a `socket`.
Connection details such as `remoteAddress` are then available directly on this
socket. Server sockets always have an underlying socket.

This remains available after the socket has been destroyed, for example to
identify the underlying connection from a [`'tlsClientError'`][] listener.

## `tls.checkServerIdentity(hostname, cert)`

<!-- YAML
Expand Down Expand Up @@ -2594,6 +2615,7 @@ added: v0.11.3
[`'secureConnect'`]: #event-secureconnect
[`'secureConnection'`]: #event-secureconnection
[`'session'`]: #event-session
[`'tlsClientError'`]: #event-tlsclienterror
[`--tls-cipher-list`]: cli.md#--tls-cipher-listlist
[`--use-bundled-ca`]: cli.md#--use-bundled-ca---use-openssl-ca
[`--use-openssl-ca`]: cli.md#--use-bundled-ca---use-openssl-ca
Expand All @@ -2609,6 +2631,7 @@ added: v0.11.3
[`net.Server`]: net.md#class-netserver
[`net.Socket`]: net.md#class-netsocket
[`net.createServer()`]: net.md#netcreateserveroptions-connectionlistener
[`new tls.TLSSocket()`]: #new-tlstlssocketsocket-options
[`server.addContext()`]: #serveraddcontexthostname-context
[`server.getTicketKeys()`]: #servergetticketkeys
[`server.listen()`]: net.md#serverlisten
Expand Down
2 changes: 2 additions & 0 deletions lib/internal/tls/wrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,8 @@ function TLSSocket(socket, opts) {
// Proxy for API compatibility
this.ssl = this._handle; // C++ TLSWrap object

this.socket = socket ?? null;

this.on('error', this._tlsError);

this._init(socket, wrap);
Expand Down
57 changes: 57 additions & 0 deletions test/parallel/test-tls-socket-underlying-socket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');

const assert = require('assert');
const fixtures = require('../common/fixtures');
const net = require('net');
const tls = require('tls');
const { duplexPair } = require('stream');

const key = fixtures.readKey('agent1-key.pem');
const cert = fixtures.readKey('agent1-cert.pem');

// Server sockets over a plain connection expose that net.Socket.
{
const server = tls.createServer({ key, cert });
let rawSocket;
server.prependListener('connection', common.mustCall((socket) => {
rawSocket = socket;
}));
server.on('secureConnection', common.mustCall((tlsSocket) => {
assert.ok(rawSocket instanceof net.Socket);
assert.strictEqual(tlsSocket.socket, rawSocket);
tlsSocket.end();
server.close();
}));
server.listen(0, common.mustCall(() => {
const client = tls.connect({
port: server.address().port,
rejectUnauthorized: false,
}, common.mustCall(() => {
assert.strictEqual(client.socket, null);
client.end();
}));
}));
}

// Server sockets over any other stream expose that stream, and still do after
// a failed handshake has destroyed them.
{
const server = tls.createServer({ key, cert, minVersion: 'TLSv1.3' });
const [serverSide, clientSide] = duplexPair();
server.on('secureConnection', common.mustNotCall());
server.on('tlsClientError', common.mustCall((err, tlsSocket) => {
assert.strictEqual(tlsSocket.socket, serverSide);
setImmediate(common.mustCall(() => {
assert.strictEqual(tlsSocket.destroyed, true);
assert.strictEqual(tlsSocket.socket, serverSide);
}));
}));
server.emit('connection', serverSide);

const client = tls.connect({ socket: clientSide, maxVersion: 'TLSv1.2' });
assert.strictEqual(client.socket, clientSide);
client.on('error', common.mustCall());
}
Loading