diff --git a/package-lock.json b/package-lock.json index 353731b..7f269f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "siteforge", - "version": "2.17.2", + "version": "2.17.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "siteforge", - "version": "2.17.2", + "version": "2.17.3", "dependencies": { "@aws-sdk/client-s3": "^3.1135.0", "@dnd-kit/core": "^6.3.1", diff --git a/package.json b/package.json index 189093c..fda0376 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "siteforge", "private": true, - "version": "2.17.2", + "version": "2.17.3", "type": "module", "scripts": { "dev": "vite", diff --git a/server.js b/server.js index d37e695..eee87a8 100644 --- a/server.js +++ b/server.js @@ -67,6 +67,7 @@ import { register as registerNuggets } from './server/routes/nuggets.js' import { register as registerNuggetsHostUpload } from './server/routes/nuggets-host-upload.js' import { register as registerNuggetsWorkflow } from './server/routes/nuggets-workflow.js' import { register as registerPodcastWorkflow } from './server/routes/podcast-workflow.js' +import { preferIpv4ForSeafile } from './server/seafile-dns.js' import { startNuggetsSeafileWatcher } from './server/nuggets-seafile-watcher.js' import { register as registerFeed } from './server/routes/feed.js' import { register as registerQrCodes } from './server/routes/qr-codes.js' @@ -74,6 +75,8 @@ import { register as registerBiblePassage } from './server/routes/bible-passage. import { register as registerNewsletter } from './server/routes/newsletter.js' import { register as registerPublic } from './server/routes/public.js' +preferIpv4ForSeafile() + const app = express() app.use(express.json({ limit: '10mb' })) const trustProxyHops = Number(process.env.TRUST_PROXY_HOPS ?? 1) diff --git a/server/seafile-dns.js b/server/seafile-dns.js new file mode 100644 index 0000000..8b6648f --- /dev/null +++ b/server/seafile-dns.js @@ -0,0 +1,30 @@ +import dns from 'node:dns' +import { SEAFILE_URL } from './config.js' + +// Alpine's resolver (musl) fails the whole lookup when a DNS server answers the IPv6 (AAAA) +// query with "no such name" even though the IPv4 answer is fine, so Node reports ENOTFOUND for +// a host that resolves. Ask for IPv4 only, and only for the Seafile host. +export function preferIpv4ForSeafile() { + let host = '' + try { + host = SEAFILE_URL ? new URL(SEAFILE_URL).hostname : '' + } catch { + return + } + if (!host) return + + const originalLookup = dns.lookup + dns.lookup = function lookup(hostname, options, callback) { + if (hostname === host) { + if (typeof options === 'function') { + callback = options + options = {} + } else if (typeof options === 'number') { + options = { family: options } + } + if (!options?.family) options = { ...options, family: 4 } + } + return originalLookup.call(this, hostname, options, callback) + } + console.log(`[seafile-dns] resolving ${host} over IPv4 only`) +}