Skip to content

Commit 1ed4e98

Browse files
authored
fix: Optimize DNS resolution logic (#602)
Updates the instance DNS name regex to the correct permissive format. See GoogleCloudPlatform/cloud-sql-go-connector#1143
1 parent dc28e53 commit 1ed4e98

3 files changed

Lines changed: 122 additions & 75 deletions

File tree

‎src/parse-instance-connection-name.ts‎

Lines changed: 16 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import {InstanceConnectionInfo} from './instance-connection-info';
1616
import {CloudSQLConnectorError} from './errors';
1717
import {resolveTxtRecord, resolveCnameRecord} from './dns-lookup';
1818

19+
export const INSTANCE_DNS_NAME_PATTERN =
20+
/^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])\.(sql|sql-psa|sql-psc)\.goog\.?$/;
21+
1922
export interface DNSFetcher {
2023
resolveConnectSettings(region: string, dnsName: string): Promise<string>;
2124
}
@@ -27,13 +30,9 @@ export function parseInstanceDNSName(dnsName: string): {
2730
suffix: string;
2831
ok: boolean;
2932
} {
30-
let name = dnsName.toLowerCase();
31-
if (name.endsWith('.')) {
32-
name = name.slice(0, -1);
33-
}
34-
35-
const parts = name.split('.');
36-
if (parts.length !== 5) {
33+
const name = dnsName.toLowerCase();
34+
const match = name.match(INSTANCE_DNS_NAME_PATTERN);
35+
if (!match) {
3736
return {
3837
instanceLabel: '',
3938
projectLabel: '',
@@ -43,35 +42,10 @@ export function parseInstanceDNSName(dnsName: string): {
4342
};
4443
}
4544

46-
if (parts[4] !== 'goog') {
47-
return {
48-
instanceLabel: '',
49-
projectLabel: '',
50-
region: '',
51-
suffix: '',
52-
ok: false,
53-
};
54-
}
55-
56-
const suffixType = parts[3];
57-
if (
58-
suffixType !== 'sql' &&
59-
suffixType !== 'sql-psa' &&
60-
suffixType !== 'sql-psc'
61-
) {
62-
return {
63-
instanceLabel: '',
64-
projectLabel: '',
65-
region: '',
66-
suffix: '',
67-
ok: false,
68-
};
69-
}
70-
71-
const instanceLabel = parts[0];
72-
const projectLabel = parts[1];
73-
const region = parts[2];
74-
const suffix = suffixType + '.goog';
45+
const instanceLabel = match[1];
46+
const projectLabel = match[2];
47+
const region = match[3];
48+
const suffix = match[4] + '.goog';
7549

7650
if (region === 'global') {
7751
return {
@@ -83,37 +57,6 @@ export function parseInstanceDNSName(dnsName: string): {
8357
};
8458
}
8559

86-
if (instanceLabel.length !== 12) {
87-
return {
88-
instanceLabel: '',
89-
projectLabel: '',
90-
region: '',
91-
suffix: '',
92-
ok: false,
93-
};
94-
}
95-
96-
// Validate instanceLabel is hex
97-
if (!/^[0-9a-f]{12}$/.test(instanceLabel)) {
98-
return {
99-
instanceLabel: '',
100-
projectLabel: '',
101-
region: '',
102-
suffix: '',
103-
ok: false,
104-
};
105-
}
106-
107-
if (!region.includes('-')) {
108-
return {
109-
instanceLabel: '',
110-
projectLabel: '',
111-
region: '',
112-
suffix: '',
113-
ok: false,
114-
};
115-
}
116-
11760
return {instanceLabel, projectLabel, region, suffix, ok: true};
11861
}
11962

@@ -178,14 +121,14 @@ export function isValidDomainName(name: string): boolean {
178121
return Boolean(matches);
179122
}
180123

181-
const instanceDNSSuffixRegex = /\.sql(-\w+)?\.goog\.?$/;
182-
const globalInstanceDNSRegex = /\.global\.sql(-\w+)?\.goog\.?$/;
183-
184124
export function isInstanceDNSName(name: string): boolean {
185125
const lower = name.toLowerCase();
186-
return (
187-
instanceDNSSuffixRegex.test(lower) && !globalInstanceDNSRegex.test(lower)
188-
);
126+
const match = lower.match(INSTANCE_DNS_NAME_PATTERN);
127+
if (!match) {
128+
return false;
129+
}
130+
const region = match[3];
131+
return region !== 'global';
189132
}
190133

191134
export function isInstanceConnectionName(name: string): boolean {

‎test/cloud-sql-instance-dns.ts‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ t.test('CloudSQLInstance DNS Lookup', async t => {
3939
expirationTime: '2033-01-06T10:00:00.232Z',
4040
};
4141
},
42+
async resolveConnectSettings() {
43+
return 'my-project:us-east1:my-instance';
44+
},
4245
};
4346

4447
let resolveARecordMock = async (): Promise<string[]> => {
@@ -161,4 +164,65 @@ t.test('CloudSQLInstance DNS Lookup', async t => {
161164

162165
t.equal(instance.host, '127.0.0.1', 'Host should use metadata IP');
163166
});
167+
168+
t.test('optimization for immutable names - custom DNS', async t => {
169+
resolveARecordMock = async () => ['10.0.0.1'];
170+
resolveTXTRecordMock = async () => ['my-project:us-east1:my-instance'];
171+
172+
const instance = await CloudSQLInstance.getCloudSQLInstance({
173+
ipType: IpAddressTypes.PUBLIC,
174+
authType: AuthTypes.PASSWORD,
175+
domainName: 'example.com',
176+
sqlAdminFetcher: fetcher,
177+
});
178+
t.after(() => instance.close());
179+
180+
t.ok(
181+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
182+
(instance as any).checkDomainID,
183+
'should enable checkDomain interval for custom DNS'
184+
);
185+
});
186+
187+
t.test(
188+
'optimization for immutable names - immutable instance DNS',
189+
async t => {
190+
resolveARecordMock = async () => ['10.0.0.1'];
191+
192+
const instance = await CloudSQLInstance.getCloudSQLInstance({
193+
ipType: IpAddressTypes.PUBLIC,
194+
authType: AuthTypes.PASSWORD,
195+
domainName: '0123456789ab.fedcba9876543.us-central1.sql-psc.goog',
196+
sqlAdminFetcher: fetcher,
197+
});
198+
t.after(() => instance.close());
199+
200+
t.notOk(
201+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
202+
(instance as any).checkDomainID,
203+
'should NOT enable checkDomain interval for immutable instance DNS'
204+
);
205+
}
206+
);
207+
208+
t.test(
209+
'optimization for immutable names - mutable global instance DNS',
210+
async t => {
211+
resolveARecordMock = async () => ['10.0.0.1'];
212+
213+
const instance = await CloudSQLInstance.getCloudSQLInstance({
214+
ipType: IpAddressTypes.PUBLIC,
215+
authType: AuthTypes.PASSWORD,
216+
domainName: '0123456789ab.fedcba9876543.global.sql-psc.goog',
217+
sqlAdminFetcher: fetcher,
218+
});
219+
t.after(() => instance.close());
220+
221+
t.ok(
222+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
223+
(instance as any).checkDomainID,
224+
'should enable checkDomain interval for mutable global instance DNS'
225+
);
226+
}
227+
);
164228
});

‎test/parse-instance-connection-name.ts‎

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,26 @@ t.test('parseInstanceDNSName', async t => {
406406
ok: true,
407407
},
408408
},
409+
{
410+
dns: 'not-hex-label.fedcba9876543.us-central1.sql-psc.goog',
411+
want: {
412+
instanceLabel: 'not-hex-label',
413+
projectLabel: 'fedcba9876543',
414+
region: 'us-central1',
415+
suffix: 'sql-psc.goog',
416+
ok: true,
417+
},
418+
},
419+
{
420+
dns: 'abc.def.uscentral.sql-psc.goog',
421+
want: {
422+
instanceLabel: 'abc',
423+
projectLabel: 'def',
424+
region: 'uscentral',
425+
suffix: 'sql-psc.goog',
426+
ok: true,
427+
},
428+
},
409429
{
410430
dns: '0123456789ab.fedcba9876543.global.sql-psc.goog',
411431
want: {
@@ -417,7 +437,7 @@ t.test('parseInstanceDNSName', async t => {
417437
},
418438
},
419439
{
420-
dns: 'not-hex-label.fedcba9876543.us-central1.sql-psc.goog',
440+
dns: '0123456789ab.fedcba9876543.us-central1.invalid-suffix.goog',
421441
want: {
422442
instanceLabel: '',
423443
projectLabel: '',
@@ -427,7 +447,27 @@ t.test('parseInstanceDNSName', async t => {
427447
},
428448
},
429449
{
430-
dns: '0123456789ab.fedcba9876543.us-central1.invalid-suffix.goog',
450+
dns: '-starts-with-hyphen.proj.region.sql.goog',
451+
want: {
452+
instanceLabel: '',
453+
projectLabel: '',
454+
region: '',
455+
suffix: '',
456+
ok: false,
457+
},
458+
},
459+
{
460+
dns: 'ends-with-hyphen-.proj.region.sql.goog',
461+
want: {
462+
instanceLabel: '',
463+
projectLabel: '',
464+
region: '',
465+
suffix: '',
466+
ok: false,
467+
},
468+
},
469+
{
470+
dns: 'empty..region.sql.goog',
431471
want: {
432472
instanceLabel: '',
433473
projectLabel: '',

0 commit comments

Comments
 (0)