Setting for specifiying the local host for port forwarding

Fixes #124581
This commit is contained in:
Alex Ross 2021-05-28 15:38:31 +02:00
parent e15f402651
commit e7776ccdcc
No known key found for this signature in database
GPG key ID: 89DDDBA66CBA7840
3 changed files with 26 additions and 11 deletions

View file

@ -8,6 +8,7 @@ import { Barrier } from 'vs/base/common/async';
import { Disposable } from 'vs/base/common/lifecycle';
import { findFreePortFaster } from 'vs/base/node/ports';
import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
import { connectRemoteAgentTunnel, IConnectionOptions, IAddressProvider, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection';
@ -15,8 +16,8 @@ import { AbstractTunnelService, RemoteTunnel } from 'vs/platform/remote/common/t
import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory';
import { ISignService } from 'vs/platform/sign/common/sign';
async function createRemoteTunnel(options: IConnectionOptions, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort?: number): Promise<RemoteTunnel> {
const tunnel = new NodeRemoteTunnel(options, tunnelRemoteHost, tunnelRemotePort, tunnelLocalPort);
async function createRemoteTunnel(options: IConnectionOptions, defaultTunnelHost: string, tunnelRemoteHost: string, tunnelRemotePort: number, tunnelLocalPort?: number): Promise<RemoteTunnel> {
const tunnel = new NodeRemoteTunnel(options, defaultTunnelHost, tunnelRemoteHost, tunnelRemotePort, tunnelLocalPort);
return tunnel.waitForReady();
}
@ -38,7 +39,7 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel {
private readonly _socketsDispose: Map<string, () => void> = new Map();
constructor(options: IConnectionOptions, tunnelRemoteHost: string, tunnelRemotePort: number, private readonly suggestedLocalPort?: number) {
constructor(options: IConnectionOptions, private readonly defaultTunnelHost: string, tunnelRemoteHost: string, tunnelRemotePort: number, private readonly suggestedLocalPort?: number) {
super();
this._options = options;
this._server = net.createServer();
@ -76,14 +77,14 @@ class NodeRemoteTunnel extends Disposable implements RemoteTunnel {
// if that fails, the method above returns 0, which works out fine below...
let address: string | net.AddressInfo | null = null;
this._server.listen(localPort, '127.0.0.1');
this._server.listen(localPort, this.defaultTunnelHost);
await this._barrier.wait();
address = <net.AddressInfo>this._server.address();
// It is possible for findFreePortFaster to return a port that there is already a server listening on. This causes the previous listen call to error out.
if (!address) {
localPort = 0;
this._server.listen(localPort, '127.0.0.1');
this._server.listen(localPort, this.defaultTunnelHost);
await this._barrier.wait();
address = <net.AddressInfo>this._server.address();
}
@ -137,11 +138,16 @@ export class BaseTunnelService extends AbstractTunnelService {
private readonly socketFactory: ISocketFactory,
@ILogService logService: ILogService,
@ISignService private readonly signService: ISignService,
@IProductService private readonly productService: IProductService
@IProductService private readonly productService: IProductService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(logService);
}
private get defaultTunnelHost(): string {
return (this.configurationService.getValue('remote.localPortHost') === 'localhost') ? '127.0.0.1' : '0.0.0.0';
}
protected retainOrCreateTunnel(addressProvider: IAddressProvider, remoteHost: string, remotePort: number, localPort: number | undefined, elevateIfNeeded: boolean, isPublic: boolean): Promise<RemoteTunnel | undefined> | undefined {
const existing = this.getTunnelFromMap(remoteHost, remotePort);
if (existing) {
@ -162,7 +168,7 @@ export class BaseTunnelService extends AbstractTunnelService {
ipcLogger: null
};
const tunnel = createRemoteTunnel(options, remoteHost, remotePort, localPort);
const tunnel = createRemoteTunnel(options, this.defaultTunnelHost, remoteHost, remotePort, localPort);
this.logService.trace('ForwardedPorts: (TunnelService) Tunnel created without provider.');
this.addTunnelToMap(remoteHost, remotePort, tunnel);
return tunnel;
@ -174,8 +180,9 @@ export class TunnelService extends BaseTunnelService {
public constructor(
@ILogService logService: ILogService,
@ISignService signService: ISignService,
@IProductService productService: IProductService
@IProductService productService: IProductService,
@IConfigurationService configurationService: IConfigurationService
) {
super(nodeSocketFactory, logService, signService, productService);
super(nodeSocketFactory, logService, signService, productService, configurationService);
}
}

View file

@ -241,6 +241,12 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
defaultSnippets: [{ body: { onAutoForward: 'ignore' } }],
markdownDescription: localize('remote.portsAttributes.defaults', "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```"),
additionalProperties: false
},
'remote.localPortHost': {
type: 'string',
enum: ['localhost', 'allInterfaces'],
default: 'localhost',
description: localize('remote.localPortHost', "Specifies the local host name that will be used for port forwarding.")
}
}
});

View file

@ -13,6 +13,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { URI } from 'vs/base/common/uri';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export class TunnelService extends BaseTunnelService {
public constructor(
@ -20,9 +21,10 @@ export class TunnelService extends BaseTunnelService {
@ISignService signService: ISignService,
@IProductService productService: IProductService,
@IRemoteAgentService _remoteAgentService: IRemoteAgentService,
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService
@IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService,
@IConfigurationService configurationService: IConfigurationService
) {
super(nodeSocketFactory, logService, signService, productService);
super(nodeSocketFactory, logService, signService, productService, configurationService);
}
override canTunnel(uri: URI): boolean {