domain check now uses external DNS server https://github.com/rejetto/hfs/discussions/346#discussioncomment-7024128
Massimo Melina committed
Sep 17, 2023 at 11:47 UTC
0c4e6d3c0dc68cc22eea22ab5e9b89aeee829b6d
3 files changed
+19
-9
central.json
+1
@@ -1,4 +1,5 @@
1
{
2
+ "dnsServers": ["1.1.1.1", "8.8.8.8"],
3
"checkServerServices": [
4
{
5
"url": "https://ports.yougetsignal.com/check-port.php",
src/api.net.ts
+16
-7
@@ -13,13 +13,13 @@ import { cert, getCertObject, getIps, getServerStatus, privateKey } from './list
13
import { getProjectInfo } from './github'
14
import { httpString } from './util-http'
15
import { exec } from 'child_process'
16
-import { apiAssertTypes, debounceAsync, HOUR, MINUTE, objSameKeys, repeat } from './misc'
16
+import { apiAssertTypes, debounceAsync, HOUR, MINUTE, objSameKeys, onlyTruthy, repeat } from './misc'
17
import acme from 'acme-client'
18
import fs from 'fs/promises'
19
import { Dict } from './misc'
20
import { createServer, RequestListener } from 'http'
21
import { Middleware } from 'koa'
22
-import { lookup } from 'dns/promises'
22
+import { lookup, Resolver } from 'dns/promises'
23
24
const client = new Client({ timeout: 4_000 })
25
const originalMethod = client.getGateway
@@ -95,12 +95,21 @@ export const acmeMiddleware: Middleware = (ctx, next) => { // koa format
95
}
96
97
async function checkDomain(domain: string) {
98
- const { address: domainIp } = await lookup(domain).catch(e => {
99
- throw e.code !== 'ENOTFOUND' ? e : new ApiError(HTTP_FAILED_DEPENDENCY, "this domain doesn't exist")
100
- })
98
+ const resolver = new Resolver()
99
+ const prjInfo = await getProjectInfo()
100
+ resolver.setServers(prjInfo.dnsServers)
101
+ const settled = await Promise.allSettled([
102
+ resolver.resolve(domain, 'A'),
103
+ resolver.resolve(domain, 'AAAA'),
104
+ lookup(domain).then(x => [x.address]),
105
+ ])
106
+ // merge all results
107
+ const ips = _.uniq(onlyTruthy(settled.map(x => x.status === 'fulfilled' && x.value)).flat())
108
+ if (!ips.length)
109
+ throw new ApiError(HTTP_FAILED_DEPENDENCY, "domain not working")
110
const { publicIp } = await getNatInfo() // do this before stopping the server
102
- if (publicIp !== domainIp)
103
- throw new ApiError(HTTP_FAILED_DEPENDENCY, `please configure your domain to point to ${publicIp} (currently on ${domainIp}) --- a change can take hours to be effective`)
111
+ if (!ips.includes(publicIp))
112
+ throw new ApiError(HTTP_FAILED_DEPENDENCY, `please configure your domain to point to ${publicIp} (currently on ${ips[0]}) --- a change can take hours to be effective`)
113
}
114
115
async function generateSSLCert(domain: string, email?: string) {
src/misc.ts
+2
-2
@@ -56,8 +56,8 @@ export function onOff(em: EventEmitter, events: { [eventName:string]: (...args:
56
}
57
}
58
59
-export function isLocalHost(c: Connection | Koa.Context) {
60
- const ip = c.socket.remoteAddress // don't use Context.ip as it is subject to proxied ips, and that's no use for localhost detection
59
+export function isLocalHost(c: Connection | Koa.Context | string) {
60
+ const ip = typeof c === 'string' ? c : c.socket.remoteAddress // don't use Context.ip as it is subject to proxied ips, and that's no use for localhost detection
61
return ip && (ip === '::1' || ip.endsWith('127.0.0.1'))
62
}
63