UNPKG

@microsoft/dev-tunnels-ssh-tcp

Version:

SSH TCP extensions library for Dev Tunnels

81 lines 4.46 kB
"use strict"; // // Copyright (c) Microsoft Corporation. All rights reserved. // Object.defineProperty(exports, "__esModule", { value: true }); exports.RemotePortForwarder = void 0; const net = require("net"); const dev_tunnels_ssh_1 = require("@microsoft/dev-tunnels-ssh"); const streamForwarder_1 = require("./streamForwarder"); const remotePortConnector_1 = require("./remotePortConnector"); /** * Receives SSH channels forwarded from a remote port and forwards them on to a local port. */ class RemotePortForwarder extends remotePortConnector_1.RemotePortConnector { /* @internal */ constructor(pfs, session, remoteIPAddress, remotePort, localHost, localPort) { super(session, remoteIPAddress, remotePort); this.pfs = pfs; this.localHost = localHost; this.localPort = localPort; } /* @internal */ async onPortChannelOpening(request, cancellation) { await RemotePortForwarder.forwardChannel(this.pfs, request, this.localHost, this.localPort, this.remotePort, this.trace, cancellation); } /* @internal */ static async forwardChannel(pfs, request, localHost, localPort, remotePort, trace, cancellation) { const channel = request.channel; const forwardedStream = await pfs.forwardedPortConnecting(remotePort !== null && remotePort !== void 0 ? remotePort : localPort, true, new dev_tunnels_ssh_1.SshStream(channel), cancellation); if (!forwardedStream) { // The event handler rejected the connection. request.failureReason = dev_tunnels_ssh_1.SshChannelOpenFailureReason.connectFailed; return; } const socket = net.createConnection({ host: localHost, port: localPort, // This option enables connection attempts for multiple resolved IP addresses, // aka "Happy Eyeballs" as described in https://datatracker.ietf.org/doc/html/rfc8305. // Effectively this enables fast connections to either 127.0.0.1 or ::1 when 'localhost' // is specified as the hostname. Note this option is available starting with Node.js // v18.13 and is enabled by default starting with Node.js v20.0. autoSelectFamily: true, // Use the minimum supported connection attempt delay when connecting to 'localhost'. // See https://nodejs.org/api/net.html#socketconnectoptions-connectlistener autoSelectFamilyAttemptTimeout: localHost === 'localhost' ? 10 : 250, }); const connectCompletion = new dev_tunnels_ssh_1.PromiseCompletionSource(); const cancellationRegistration = cancellation ? cancellation.onCancellationRequested(() => socket.destroy(new Error('Cancelled.'))) : null; try { socket.once('connect', () => { connectCompletion.resolve(); }); socket.once('error', (e) => { connectCompletion.reject(e); }); await connectCompletion.promise; } catch (e) { if (!(e instanceof Error) || (cancellation === null || cancellation === void 0 ? void 0 : cancellation.isCancellationRequested)) { throw e; } trace(dev_tunnels_ssh_1.TraceLevel.Warning, dev_tunnels_ssh_1.SshTraceEventIds.portForwardConnectionFailed, `PortForwardingService connection ` + `to ${localHost}:${localPort} failed: ${e.message}`, e); request.failureReason = dev_tunnels_ssh_1.SshChannelOpenFailureReason.connectFailed; request.failureDescription = e.message; } finally { cancellationRegistration === null || cancellationRegistration === void 0 ? void 0 : cancellationRegistration.dispose(); } // TODO: Set socket options? const streamForwarder = new streamForwarder_1.StreamForwarder(socket, forwardedStream, channel.session.trace); trace(dev_tunnels_ssh_1.TraceLevel.Info, dev_tunnels_ssh_1.SshTraceEventIds.portForwardConnectionOpened, `${channel.session} PortForwardingService forwarded channel ` + `#${channel.channelId} connection to ${localHost}:${localPort}.`); pfs.streamForwarders.push(streamForwarder); } } exports.RemotePortForwarder = RemotePortForwarder; //# sourceMappingURL=remotePortForwarder.js.map