Skip to content

Commit d2cbc55

Browse files
authored
Add timeout to dns lookup and progress notification (#55)
* Add timeout to dns lookup * Add progress notification
1 parent affd321 commit d2cbc55

File tree

4 files changed

+159
-148
lines changed

4 files changed

+159
-148
lines changed

src/local-ssh/common.ts

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import dns from 'dns';
7-
import { GetWorkspaceAuthInfoResponse } from '../proto/typescript/ipc/v1/ipc';
8-
import { ILogService } from '../services/logService';
97

108
// This public key is safe to be public since we only use it to verify local-ssh connections.
119
const HOST_KEY = 'LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR0hBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJHMHdhd0lCQVFRZ1QwcXg1eEJUVmc4TUVJbUUKZmN4RXRZN1dmQVVsM0JYQURBK2JYREsyaDZlaFJBTkNBQVJlQXo0RDVVZXpqZ0l1SXVOWXpVL3BCWDdlOXoxeApvZUN6UklqcGdCUHozS0dWRzZLYXV5TU5YUm95a21YSS9BNFpWaW9nd2Vjb0FUUjRUQ2FtWm1ScAotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0tCg==';
@@ -41,39 +39,40 @@ export interface DaemonOptions {
4139
logFilePath: string;
4240
}
4341

44-
export type WorkspaceAuthInfo = GetWorkspaceAuthInfoResponse;
45-
46-
47-
export function isDNSPointToLocalhost(logService: ILogService, domain: string): Promise<boolean> {
48-
return new Promise(resolve => {
49-
dns.lookup(domain, { all: true }, (err, addresses) => {
50-
if (err) {
51-
resolve(false);
52-
} else {
53-
for (const addr of addresses) {
54-
if ((addr.family === 4 && addr.address === '127.0.0.1') || (addr.family === 6 && addr.address === '::1')) {
55-
resolve(true);
56-
return;
42+
export function isDNSPointToLocalhost(domain: string, timeout: number = 10000): Promise<boolean> {
43+
return Promise.race([
44+
new Promise<boolean>(resolve => {
45+
dns.lookup(domain, { all: true }, (err, addresses) => {
46+
if (err) {
47+
resolve(false);
48+
} else {
49+
for (const addr of addresses) {
50+
if ((addr.family === 4 && addr.address === '127.0.0.1') || (addr.family === 6 && addr.address === '::1')) {
51+
resolve(true);
52+
return;
53+
}
5754
}
55+
resolve(false);
5856
}
59-
logService.warn('current domain is not point to localhost', domain, addresses);
60-
resolve(false);
61-
}
62-
});
63-
});
57+
});
58+
}),
59+
new Promise<boolean>(resolve => setTimeout(() => resolve(false), timeout))
60+
]);
6461
}
6562

66-
export function isDomainConnectable(logService: ILogService, domain: string): Promise<boolean> {
67-
return new Promise(resolve => {
68-
dns.lookup(domain, (err, _address) => {
69-
if (err) {
70-
logService.warn('current domain is not connectable', domain, err);
71-
resolve(false);
72-
} else {
73-
resolve(true);
74-
}
75-
});
76-
});
63+
export function isDomainConnectable(domain: string, timeout: number = 10000): Promise<boolean> {
64+
return Promise.race([
65+
new Promise<boolean>(resolve => {
66+
dns.lookup(domain, (err, _address) => {
67+
if (err) {
68+
resolve(false);
69+
} else {
70+
resolve(true);
71+
}
72+
});
73+
}),
74+
new Promise<boolean>(resolve => setTimeout(() => resolve(false), timeout))
75+
]);
7776
}
7877

7978
export const GitpodDefaultLocalhost = 'lssh.gitpod.io';
@@ -84,4 +83,4 @@ export function getRunningExtensionVersion() {
8483

8584
export function getDaemonVersion() {
8685
return process.env.DAEMON_VERSION ?? '0.0.1';
87-
}
86+
}

src/local-ssh/server.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44
*--------------------------------------------------------------------------------------------*/
55

66
import { Server as GrpcServer } from 'nice-grpc';
7-
import { WorkspaceAuthInfo, ExitCode, exitProcess, getHostKey, getDaemonVersion, getRunningExtensionVersion } from './common';
7+
import { ExitCode, exitProcess, getHostKey, getDaemonVersion, getRunningExtensionVersion } from './common';
88
import { LocalSSHServiceImpl, startLocalSSHService } from './ipc/localssh';
99
import { SupervisorSSHTunnel } from './sshTunnel';
1010
import { ILogService } from '../services/logService';
1111
import { SshServer, SshClient } from '@microsoft/dev-tunnels-ssh-tcp';
1212
import { NodeStream, SshClientCredentials, SshClientSession, SshDisconnectReason, SshSessionConfiguration } from '@microsoft/dev-tunnels-ssh';
1313
import { importKeyBytes } from '@microsoft/dev-tunnels-ssh-keys';
1414
import { parsePrivateKey } from 'sshpk';
15-
import { SendLocalSSHUserFlowStatusRequest_Code, SendLocalSSHUserFlowStatusRequest_ConnType, SendLocalSSHUserFlowStatusRequest_Status } from '../proto/typescript/ipc/v1/ipc';
15+
import { GetWorkspaceAuthInfoResponse, SendLocalSSHUserFlowStatusRequest_Code, SendLocalSSHUserFlowStatusRequest_ConnType, SendLocalSSHUserFlowStatusRequest_Status } from '../proto/typescript/ipc/v1/ipc';
1616
import { PipeExtensions } from './patch/pipeExtension';
1717

1818
// TODO(local-ssh): Remove me after direct ssh works with @microsft/dev-tunnels-ssh
@@ -116,7 +116,7 @@ export class LocalSSHGatewayServer {
116116
});
117117
}
118118

119-
private async tryDirectSSH(workspaceInfo: WorkspaceAuthInfo): Promise<SshClientSession | undefined> {
119+
private async tryDirectSSH(workspaceInfo: GetWorkspaceAuthInfoResponse): Promise<SshClientSession | undefined> {
120120
try {
121121
const connConfig = {
122122
host: `${workspaceInfo.workspaceId}.ssh.${workspaceInfo.workspaceHost}`,
@@ -153,7 +153,7 @@ export class LocalSSHGatewayServer {
153153
return;
154154
}
155155

156-
private async getTunnelSSHConfig(workspaceInfo: WorkspaceAuthInfo): Promise<SshClientSession> {
156+
private async getTunnelSSHConfig(workspaceInfo: GetWorkspaceAuthInfoResponse): Promise<SshClientSession> {
157157
const ssh = new SupervisorSSHTunnel(this.logger, workspaceInfo, this.localsshService);
158158
const connConfig = await ssh.establishTunnel();
159159
const config = new SshSessionConfiguration();

src/local-ssh/sshTunnel.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import { CreateSSHKeyPairRequest, CreateSSHKeyPairResponse } from '@gitpod/super
1111
import { NodeHttpTransport } from '@improbable-eng/grpc-web-node-http-transport';
1212
import { grpc } from '@improbable-eng/grpc-web';
1313
import { BrowserHeaders } from 'browser-headers';
14-
import { WorkspaceAuthInfo, getDaemonVersion, getRunningExtensionVersion } from './common';
14+
import { getDaemonVersion, getRunningExtensionVersion } from './common';
1515
import { ILogService } from '../services/logService';
1616
import { LocalSSHServiceImpl } from './ipc/localssh';
17-
import { SendLocalSSHUserFlowStatusRequest_Code, SendLocalSSHUserFlowStatusRequest_ConnType, SendLocalSSHUserFlowStatusRequest_Status } from '../proto/typescript/ipc/v1/ipc';
17+
import { GetWorkspaceAuthInfoResponse, SendLocalSSHUserFlowStatusRequest_Code, SendLocalSSHUserFlowStatusRequest_ConnType, SendLocalSSHUserFlowStatusRequest_Status } from '../proto/typescript/ipc/v1/ipc';
1818

1919
grpc.setDefaultTransport(NodeHttpTransport());
2020

@@ -44,7 +44,7 @@ export class SupervisorSSHTunnel {
4444

4545
constructor(
4646
private readonly logger: ILogService,
47-
readonly workspaceInfo: WorkspaceAuthInfo,
47+
readonly workspaceInfo: GetWorkspaceAuthInfoResponse,
4848
private readonly localsshService: LocalSSHServiceImpl,
4949
) { }
5050

0 commit comments

Comments
 (0)