diff --git a/src/app.ts b/src/app.ts index 889ec260..e76d3c92 100644 --- a/src/app.ts +++ b/src/app.ts @@ -26,6 +26,80 @@ interface DnsLookupOpts { family: number; } +/* + * ===================================================== + * NOTE: This is required since Alpine/musl-based images + * do not support mDNS name resolution in the musl libs. + * + * In order to support .local mDNS names in development + * and on openBalena setups, this extra code will perform + * the lookup instead of passing it to the built-in + * function. + * ================================================== + */ +async function mdnsLookup( + name: string, + opts: Partial | number | null | undefined, + cb: DnsLookupCallback, +) { + // determine which resolvers to use... + const getResolvers = () => { + // logic to determine the families based on Node docs. + // See: https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback + const families = (() => { + // strictly defined... + if (opts === 4 || opts === 6) { + return [opts as number]; + } + + // opts is passed, not a number and the `family` parameter is passed... + if (opts && typeof opts !== 'number' && opts.family) { + return [opts.family]; + } + + // default to resolve both v4 and v6... + return [4, 6]; + })(); + + // map them and return... + return families.map(async (family) => { + let address = ''; + try { + address = await mdnsResolver.resolve(name, family === 6 ? 'AAAA' : 'A'); + } catch { + /* noop */ + } + + return { address, family }; + }); + }; + + // resolve the addresses... + const results = await Promise.all(getResolvers()); + // remove any that didn't resolve... + let allAddresses = results.filter((result) => result.address !== ''); + + // unless the results should be returned verbatim, sort them so v4 comes first... + if (opts && typeof opts !== 'number' && !opts.verbatim) { + allAddresses = allAddresses.sort((a, b) => a.family - b.family); + } + + // see if we resolved anything... + if (allAddresses.length === 0) { + // nothing! return a suitable error... + return cb(new DnsLookupError()); + } + + // all the addresses were requested... + if (opts && typeof opts !== 'number' && opts.all) { + return cb(null, allAddresses); + } + + // only a single address was requested... + const [{ address: addr, family: fmly }] = allAddresses; + return cb(null, addr, fmly); +} + // This was originally wrapped in a do block in // coffeescript, and it's not clear now why that was the // case, so I'm going to maintain that behaviour @@ -45,79 +119,24 @@ interface DnsLookupOpts { return lookup(name, { verbatim: true }, opts); } - /* ===================================================== - * NOTE: This is required since Alpine/musl-based images - * do not support mDNS name resolution in the musl libs. - * - * In order to support .local mDNS names in development - * and on openBalena setups, this extra code will perform - * the lookup instead of passing it to the built-in - * function. - ================================================== */ - if (name && name.endsWith('.local')) { - // determine which resolvers to use... - const getResolvers = () => { - // logic to determine the families based on Node docs. - // See: https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback - const families = (() => { - // strictly defined... - if (opts === 4 || opts === 6) { - return [opts as number]; - } - - // opts is passed, not a number and the `family` parameter is passed... - if (opts && typeof opts !== 'number' && opts.family) { - return [opts.family]; - } - - // default to resolve both v4 and v6... - return [4, 6]; - })(); - - // map them and return... - return families.map((family) => { - return mdnsResolver - .resolve(name, family === 6 ? 'AAAA' : 'A') - .catch(() => { - return ''; - }) - .then((address) => { - return { - address, - family, - }; - }); - }); - }; - - // resolve the addresses... - return Promise.all(getResolvers()).then((results) => { - // remove any that didn't resolve... - let allAddresses = results.filter((result) => result.address !== ''); - - // unless the results should be returned verbatim, sort them so v4 comes first... - if (opts && typeof opts !== 'number' && !opts.verbatim) { - allAddresses = allAddresses.sort((a, b) => a.family - b.family); + // Try a regular dns lookup first + return lookup( + name, + Object.assign({ verbatim: true }, opts), + (error: any, address: string, family: number) => { + if (error == null) { + return cb(null, address, family); } - // see if we resolved anything... - if (allAddresses.length === 0) { - // nothing! return a suitable error... - return cb(new DnsLookupError()); + // If the regular lookup fails, we perform a mdns lookup if the + // name ends with .local + if (name && name.endsWith('.local')) { + return mdnsLookup(name, opts, cb); } - // all the addresses were requested... - if (opts && typeof opts !== 'number' && opts.all) { - return cb(null, allAddresses); - } - - // only a single address was requested... - const [{ address, family }] = allAddresses; - return cb(null, address, family); - }); - } - - return lookup(name, Object.assign({ verbatim: true }, opts), cb); + return cb(error); + }, + ); }; })();