Fix duplicate port forwarding for statically forwarded ports (#163899)

* Fix duplicate port in view

* Include localhost address when resolving external
This commit is contained in:
Alex Ross
2022-10-18 20:08:21 +02:00
committed by GitHub
parent 58574650b6
commit b09701ac1b
3 changed files with 20 additions and 2 deletions

View File

@@ -126,6 +126,7 @@ export interface ITunnelService {
canTunnel(uri: URI): boolean; canTunnel(uri: URI): boolean;
openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined; openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded?: boolean, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined;
getExistingTunnel(remoteHost: string, remotePort: number): Promise<RemoteTunnel | undefined>;
setEnvironmentTunnel(remoteHost: string, remotePort: number, localAddress: string, privacy: string, protocol: string): void; setEnvironmentTunnel(remoteHost: string, remotePort: number, localAddress: string, privacy: string, protocol: string): void;
closeTunnel(remoteHost: string, remotePort: number): Promise<void>; closeTunnel(remoteHost: string, remotePort: number): Promise<void>;
setTunnelProvider(provider: ITunnelProvider | undefined): IDisposable; setTunnelProvider(provider: ITunnelProvider | undefined): IDisposable;
@@ -282,6 +283,19 @@ export abstract class AbstractTunnelService implements ITunnelService {
})); }));
} }
async getExistingTunnel(remoteHost: string, remotePort: number): Promise<RemoteTunnel | undefined> {
if (isAllInterfaces(remoteHost) || isLocalhost(remoteHost)) {
remoteHost = LOCALHOST_ADDRESSES[0];
}
const existing = this.getTunnelFromMap(remoteHost, remotePort);
if (existing) {
++existing.refcount;
return existing.value;
}
return undefined;
}
openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded: boolean = false, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined { openTunnel(addressProvider: IAddressProvider | undefined, remoteHost: string | undefined, remotePort: number, localPort?: number, elevateIfNeeded: boolean = false, privacy?: string, protocol?: string): Promise<RemoteTunnel | undefined> | undefined {
this.logService.trace(`ForwardedPorts: (TunnelService) openTunnel request for ${remoteHost}:${remotePort} on local port ${localPort}.`); this.logService.trace(`ForwardedPorts: (TunnelService) openTunnel request for ${remoteHost}:${remotePort} on local port ${localPort}.`);
if (!addressProvider) { if (!addressProvider) {

View File

@@ -769,13 +769,16 @@ export class NativeWindow extends Disposable {
return (await this.remoteAuthorityResolverService.resolveAuthority(remoteAuthority)).authority; return (await this.remoteAuthorityResolverService.resolveAuthority(remoteAuthority)).authority;
} }
} : undefined; } : undefined;
const tunnel = await this.tunnelService.openTunnel(addressProvider, portMappingRequest.address, portMappingRequest.port); let tunnel = await this.tunnelService.getExistingTunnel(portMappingRequest.address, portMappingRequest.port);
if (!tunnel) {
tunnel = await this.tunnelService.openTunnel(addressProvider, portMappingRequest.address, portMappingRequest.port);
}
if (tunnel) { if (tunnel) {
const addressAsUri = URI.parse(tunnel.localAddress); const addressAsUri = URI.parse(tunnel.localAddress);
const resolved = addressAsUri.scheme.startsWith(uri.scheme) ? addressAsUri : uri.with({ authority: tunnel.localAddress }); const resolved = addressAsUri.scheme.startsWith(uri.scheme) ? addressAsUri : uri.with({ authority: tunnel.localAddress });
return { return {
resolved, resolved,
dispose: () => tunnel.dispose(), dispose: () => tunnel?.dispose(),
}; };
} }
} }

View File

@@ -473,6 +473,7 @@ export class TunnelModel extends Disposable {
this._register(this.tunnelService.onTunnelOpened(async (tunnel) => { this._register(this.tunnelService.onTunnelOpened(async (tunnel) => {
const key = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort); const key = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort);
if (!mapHasAddressLocalhostOrAllInterfaces(this.forwarded, tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort) if (!mapHasAddressLocalhostOrAllInterfaces(this.forwarded, tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort)
&& !mapHasAddressLocalhostOrAllInterfaces(this.detected, tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort)
&& !mapHasAddressLocalhostOrAllInterfaces(this.inProgress, tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort) && !mapHasAddressLocalhostOrAllInterfaces(this.inProgress, tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort)
&& tunnel.localAddress) { && tunnel.localAddress) {
const matchingCandidate = mapHasAddressLocalhostOrAllInterfaces(this._candidates ?? new Map(), tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort); const matchingCandidate = mapHasAddressLocalhostOrAllInterfaces(this._candidates ?? new Map(), tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort);