mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2025-12-24 12:19:41 +00:00
Rename files
This commit is contained in:
163
ts/util/dns.node.ts
Normal file
163
ts/util/dns.node.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
// Copyright 2023 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import type {
|
||||
LookupOneOptions,
|
||||
LookupAllOptions,
|
||||
LookupAddress,
|
||||
lookup as nodeLookup,
|
||||
} from 'node:dns';
|
||||
import * as electron from 'electron';
|
||||
import type { ResolvedHost, ResolvedEndpoint } from 'electron';
|
||||
import pTimeout from 'p-timeout';
|
||||
|
||||
import { strictAssert } from './assert.std.js';
|
||||
import { drop } from './drop.std.js';
|
||||
import type { DNSFallbackType } from '../types/DNSFallback.std.js';
|
||||
import { SECOND } from './durations/index.std.js';
|
||||
|
||||
const LOOKUP_TIMEOUT_MS = 5 * SECOND;
|
||||
const fallbackAddrs = new Map<string, ReadonlyArray<ResolvedEndpoint>>();
|
||||
|
||||
export function setFallback(dnsFallback: DNSFallbackType): void {
|
||||
fallbackAddrs.clear();
|
||||
for (const { domain, endpoints } of dnsFallback) {
|
||||
fallbackAddrs.set(domain, endpoints);
|
||||
}
|
||||
}
|
||||
|
||||
let ipv6Enabled = true;
|
||||
|
||||
export function setIPv6Enabled(value: boolean): void {
|
||||
ipv6Enabled = value;
|
||||
}
|
||||
|
||||
function lookupAll(
|
||||
hostname: string,
|
||||
opts: LookupOneOptions | LookupAllOptions,
|
||||
callback: (
|
||||
err: NodeJS.ErrnoException | null,
|
||||
addresses: string | Array<LookupAddress>,
|
||||
family?: number
|
||||
) => void
|
||||
): void {
|
||||
// Node.js support various signatures, but we only support one.
|
||||
strictAssert(typeof opts === 'object', 'missing options');
|
||||
strictAssert(typeof callback === 'function', 'missing callback');
|
||||
|
||||
async function run() {
|
||||
let result: Pick<ResolvedHost, 'endpoints'>;
|
||||
|
||||
let queryType: 'A' | 'AAAA' | undefined;
|
||||
if (opts.family === 4) {
|
||||
queryType = 'A';
|
||||
} else if (opts.family === 6) {
|
||||
queryType = 'AAAA';
|
||||
}
|
||||
|
||||
try {
|
||||
if (electron.net) {
|
||||
// Main process
|
||||
result = await pTimeout(
|
||||
electron.net.resolveHost(hostname, {
|
||||
queryType,
|
||||
}),
|
||||
LOOKUP_TIMEOUT_MS,
|
||||
'lookupAll: Electron lookup timed out'
|
||||
);
|
||||
} else {
|
||||
// Renderer
|
||||
result = await pTimeout(
|
||||
electron.ipcRenderer.invoke('net.resolveHost', hostname, queryType),
|
||||
LOOKUP_TIMEOUT_MS,
|
||||
'lookupAll: Electron lookup timed out'
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
const fallback = fallbackAddrs.get(hostname);
|
||||
if (fallback) {
|
||||
result = { endpoints: fallback.slice() };
|
||||
} else {
|
||||
callback(error, []);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let addresses = result.endpoints.map(({ address, family }) => {
|
||||
let numericFamily = -1;
|
||||
if (family === 'ipv4') {
|
||||
numericFamily = 4;
|
||||
} else if (family === 'ipv6') {
|
||||
numericFamily = 6;
|
||||
}
|
||||
return {
|
||||
address,
|
||||
family: numericFamily,
|
||||
};
|
||||
});
|
||||
|
||||
if (!ipv6Enabled) {
|
||||
const ipv4Only = addresses.filter(({ family }) => family !== 6);
|
||||
if (ipv4Only.length !== 0) {
|
||||
addresses = ipv4Only;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opts.all) {
|
||||
const random = addresses.at(Math.floor(Math.random() * addresses.length));
|
||||
if (random === undefined) {
|
||||
callback(new Error(`Hostname: ${hostname} cannot be resolved`), '', -1);
|
||||
return;
|
||||
}
|
||||
callback(null, random.address, random.family);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(null, addresses);
|
||||
}
|
||||
|
||||
drop(run());
|
||||
}
|
||||
|
||||
export function interleaveAddresses(
|
||||
addresses: ReadonlyArray<LookupAddress>
|
||||
): Array<LookupAddress> {
|
||||
const firstAddr = addresses.find(
|
||||
({ family }) => family === 4 || family === 6
|
||||
);
|
||||
if (!firstAddr) {
|
||||
throw new Error('interleaveAddresses: no addresses to interleave');
|
||||
}
|
||||
|
||||
const v4 = addresses.filter(({ family }) => family === 4);
|
||||
const v6 = addresses.filter(({ family }) => family === 6);
|
||||
|
||||
// Interleave addresses for Happy Eyeballs, but keep the first address
|
||||
// type from the DNS response first in the list.
|
||||
const interleaved = new Array<LookupAddress>();
|
||||
while (v4.length !== 0 || v6.length !== 0) {
|
||||
const v4Entry = v4.pop();
|
||||
const v6Entry = v6.pop();
|
||||
|
||||
if (firstAddr.family === 4) {
|
||||
if (v4Entry !== undefined) {
|
||||
interleaved.push(v4Entry);
|
||||
}
|
||||
if (v6Entry !== undefined) {
|
||||
interleaved.push(v6Entry);
|
||||
}
|
||||
} else {
|
||||
if (v6Entry !== undefined) {
|
||||
interleaved.push(v6Entry);
|
||||
}
|
||||
if (v4Entry !== undefined) {
|
||||
interleaved.push(v4Entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return interleaved;
|
||||
}
|
||||
|
||||
// Note: `nodeLookup` has a complicated type due to compatibility requirements.
|
||||
export const electronLookup = lookupAll as typeof nodeLookup;
|
||||
Reference in New Issue
Block a user