roster-server 2.2.6 → 2.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const legacyCli = require('acme-dns-01-cli');
|
|
4
4
|
const log = require('lemonlog')('acme-dns-01');
|
|
5
5
|
const dns = require('node:dns').promises;
|
|
6
|
+
const { execFileSync } = require('node:child_process');
|
|
6
7
|
let envFileLoadAttempted = false;
|
|
7
8
|
|
|
8
9
|
function loadEnvFileSafely() {
|
|
@@ -115,11 +116,12 @@ module.exports.create = function create(config = {}) {
|
|
|
115
116
|
? config.dnsResolvers.map((s) => String(s).trim()).filter(Boolean)
|
|
116
117
|
: parseResolvers(process.env.ROSTER_DNS_RESOLVERS);
|
|
117
118
|
const effectiveResolvers = configuredResolvers.length > 0 ? configuredResolvers : ['1.1.1.1', '8.8.8.8'];
|
|
118
|
-
const
|
|
119
|
+
const staticResolverClients = effectiveResolvers.map((server) => {
|
|
119
120
|
const resolver = new dns.Resolver();
|
|
120
121
|
resolver.setServers([server]);
|
|
121
122
|
return { server, resolver };
|
|
122
123
|
});
|
|
124
|
+
const authoritativeResolverClientsByHost = new Map();
|
|
123
125
|
const normalizeProvider = (value) => String(value || '').trim().toLowerCase();
|
|
124
126
|
const configuredProvider = normalizeProvider(
|
|
125
127
|
config.provider
|
|
@@ -149,18 +151,118 @@ module.exports.create = function create(config = {}) {
|
|
|
149
151
|
return candidate ? String(candidate).trim() : '';
|
|
150
152
|
}
|
|
151
153
|
|
|
154
|
+
function zoneCandidatesFromDnsHost(dnsHost) {
|
|
155
|
+
const normalized = String(dnsHost || '')
|
|
156
|
+
.replace(/^_acme-challenge\./, '')
|
|
157
|
+
.replace(/^_greenlock-[^.]+\./, '')
|
|
158
|
+
.replace(/\.$/, '')
|
|
159
|
+
.toLowerCase();
|
|
160
|
+
if (!normalized) return [];
|
|
161
|
+
|
|
162
|
+
const labels = normalized.split('.').filter(Boolean);
|
|
163
|
+
const candidates = [];
|
|
164
|
+
for (let i = 0; i <= labels.length - 2; i += 1) {
|
|
165
|
+
candidates.push(labels.slice(i).join('.'));
|
|
166
|
+
}
|
|
167
|
+
return candidates;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function resolveAuthoritativeResolverClients(dnsHost) {
|
|
171
|
+
const cached = authoritativeResolverClientsByHost.get(dnsHost);
|
|
172
|
+
if (cached) return cached;
|
|
173
|
+
|
|
174
|
+
const candidates = zoneCandidatesFromDnsHost(dnsHost);
|
|
175
|
+
for (const zone of candidates) {
|
|
176
|
+
let nsRecords = [];
|
|
177
|
+
try {
|
|
178
|
+
nsRecords = await dns.resolveNs(zone);
|
|
179
|
+
} catch {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (!Array.isArray(nsRecords) || nsRecords.length === 0) continue;
|
|
183
|
+
|
|
184
|
+
const clients = [];
|
|
185
|
+
for (const nsNameRaw of nsRecords) {
|
|
186
|
+
const nsName = String(nsNameRaw || '').replace(/\.$/, '');
|
|
187
|
+
if (!nsName) continue;
|
|
188
|
+
let ips = [];
|
|
189
|
+
try {
|
|
190
|
+
ips = await dns.resolve4(nsName);
|
|
191
|
+
} catch {}
|
|
192
|
+
if (ips.length === 0) {
|
|
193
|
+
try {
|
|
194
|
+
ips = await dns.resolve6(nsName);
|
|
195
|
+
} catch {}
|
|
196
|
+
}
|
|
197
|
+
for (const ip of ips) {
|
|
198
|
+
try {
|
|
199
|
+
const resolver = new dns.Resolver();
|
|
200
|
+
resolver.setServers([ip]);
|
|
201
|
+
clients.push({ server: `${nsName}/${ip}`, resolver });
|
|
202
|
+
} catch {}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (clients.length > 0) {
|
|
207
|
+
authoritativeResolverClientsByHost.set(dnsHost, clients);
|
|
208
|
+
return clients;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
authoritativeResolverClientsByHost.set(dnsHost, []);
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
|
|
152
216
|
async function resolveTxtRecords(dnsHost) {
|
|
153
217
|
const records = [];
|
|
154
218
|
const errors = [];
|
|
219
|
+
const authClients = await resolveAuthoritativeResolverClients(dnsHost);
|
|
220
|
+
const resolverClients = [...staticResolverClients, ...authClients];
|
|
221
|
+
const seenServers = new Set();
|
|
155
222
|
|
|
156
223
|
for (const { server, resolver } of resolverClients) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
224
|
+
if (seenServers.has(server)) continue;
|
|
225
|
+
seenServers.add(server);
|
|
226
|
+
|
|
227
|
+
// Primary path: query with dig directly (more reliable under Bun).
|
|
228
|
+
const serverTarget = String(server || '').includes('/') ? String(server).split('/').pop() : String(server || '');
|
|
229
|
+
let digAttempted = false;
|
|
230
|
+
if (typeof execFileSync === 'function' && serverTarget) {
|
|
231
|
+
digAttempted = true;
|
|
232
|
+
try {
|
|
233
|
+
const output = execFileSync('dig', ['+short', 'TXT', dnsHost, `@${serverTarget}`], {
|
|
234
|
+
encoding: 'utf8',
|
|
235
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
236
|
+
timeout: 4000
|
|
237
|
+
});
|
|
238
|
+
const lines = String(output || '')
|
|
239
|
+
.split('\n')
|
|
240
|
+
.map((line) => line.trim())
|
|
241
|
+
.filter(Boolean);
|
|
242
|
+
if (lines.length > 0) {
|
|
243
|
+
for (const line of lines) {
|
|
244
|
+
const normalized = normalizeTxtChunk(line);
|
|
245
|
+
if (normalized) records.push([normalized]);
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
errors.push(`${server}:ENOTFOUND`);
|
|
249
|
+
}
|
|
250
|
+
continue;
|
|
251
|
+
} catch (error) {
|
|
252
|
+
errors.push(`${server}:DIG_${error?.code || error?.signal || 'ERROR'}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Fallback path only if dig is unavailable/failed unexpectedly.
|
|
257
|
+
if (!digAttempted || records.length === 0) {
|
|
258
|
+
try {
|
|
259
|
+
const result = await resolver.resolveTxt(dnsHost);
|
|
260
|
+
if (Array.isArray(result)) {
|
|
261
|
+
records.push(...result);
|
|
262
|
+
}
|
|
263
|
+
} catch (error) {
|
|
264
|
+
errors.push(`${server}:${error?.code || error?.message || error}`);
|
|
161
265
|
}
|
|
162
|
-
} catch (error) {
|
|
163
|
-
errors.push(`${server}:${error?.code || error?.message || error}`);
|
|
164
266
|
}
|
|
165
267
|
}
|
|
166
268
|
return { records, errors };
|