@serve.zone/dcrouter 15.0.1 → 15.0.3

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.
Files changed (117) hide show
  1. package/deno.json +1 -1
  2. package/dist_serve/bundle.js +768 -768
  3. package/dist_ts/00_commitinfo_data.js +1 -1
  4. package/dist_ts/acme/classes.smartacme-lifecycle.d.ts +25 -0
  5. package/dist_ts/acme/classes.smartacme-lifecycle.js +144 -0
  6. package/dist_ts/acme/index.d.ts +1 -0
  7. package/dist_ts/acme/index.js +2 -1
  8. package/dist_ts/classes.dcrouter.d.ts +21 -139
  9. package/dist_ts/classes.dcrouter.js +71 -1585
  10. package/dist_ts/dns/classes.dns-server-runtime.d.ts +37 -0
  11. package/dist_ts/dns/classes.dns-server-runtime.js +449 -0
  12. package/dist_ts/dns/index.d.ts +1 -0
  13. package/dist_ts/dns/index.js +2 -1
  14. package/dist_ts/email/classes.accepted-email-spool.d.ts +55 -0
  15. package/dist_ts/email/classes.accepted-email-spool.js +345 -0
  16. package/dist_ts/email/classes.email-route-builder.d.ts +28 -0
  17. package/dist_ts/email/classes.email-route-builder.js +260 -0
  18. package/dist_ts/email/index.d.ts +2 -0
  19. package/dist_ts/email/index.js +3 -1
  20. package/dist_ts/opsserver/handlers/gatewayclient.handler.js +10 -8
  21. package/dist_ts/remoteingress/classes.hub-lifecycle.d.ts +27 -0
  22. package/dist_ts/remoteingress/classes.hub-lifecycle.js +241 -0
  23. package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +1 -2
  24. package/dist_ts/remoteingress/index.d.ts +1 -0
  25. package/dist_ts/remoteingress/index.js +2 -1
  26. package/dist_ts/security/classes.route-policy-augmenter.d.ts +22 -0
  27. package/dist_ts/security/classes.route-policy-augmenter.js +120 -0
  28. package/dist_ts/security/index.d.ts +1 -0
  29. package/dist_ts/security/index.js +2 -1
  30. package/dist_ts/vpn/classes.vpn-access-resolver.d.ts +34 -0
  31. package/dist_ts/vpn/classes.vpn-access-resolver.js +101 -0
  32. package/dist_ts/vpn/index.d.ts +1 -0
  33. package/dist_ts/vpn/index.js +2 -1
  34. package/dist_ts_migrations/index.js +92 -9
  35. package/dist_ts_web/00_commitinfo_data.js +1 -1
  36. package/dist_ts_web/appstate/acme.d.ts +17 -0
  37. package/dist_ts_web/appstate/acme.js +64 -0
  38. package/dist_ts_web/appstate/certificates.d.ts +37 -0
  39. package/dist_ts_web/appstate/certificates.js +107 -0
  40. package/dist_ts_web/appstate/config.d.ts +9 -0
  41. package/dist_ts_web/appstate/config.js +35 -0
  42. package/dist_ts_web/appstate/domains.d.ts +80 -0
  43. package/dist_ts_web/appstate/domains.js +324 -0
  44. package/dist_ts_web/appstate/email-domains.d.ts +25 -0
  45. package/dist_ts_web/appstate/email-domains.js +104 -0
  46. package/dist_ts_web/appstate/email-ops.d.ts +10 -0
  47. package/dist_ts_web/appstate/email-ops.js +40 -0
  48. package/dist_ts_web/appstate/login.d.ts +30 -0
  49. package/dist_ts_web/appstate/login.js +83 -0
  50. package/dist_ts_web/appstate/logs.d.ts +16 -0
  51. package/dist_ts_web/appstate/logs.js +27 -0
  52. package/dist_ts_web/appstate/network.d.ts +50 -0
  53. package/dist_ts_web/appstate/network.js +122 -0
  54. package/dist_ts_web/appstate/profiles-targets.d.ts +45 -0
  55. package/dist_ts_web/appstate/profiles-targets.js +173 -0
  56. package/dist_ts_web/appstate/remoteingress.d.ts +47 -0
  57. package/dist_ts_web/appstate/remoteingress.js +204 -0
  58. package/dist_ts_web/appstate/routes.d.ts +76 -0
  59. package/dist_ts_web/appstate/routes.js +316 -0
  60. package/dist_ts_web/appstate/runtime.d.ts +1 -0
  61. package/dist_ts_web/appstate/runtime.js +276 -0
  62. package/dist_ts_web/appstate/security.d.ts +29 -0
  63. package/dist_ts_web/appstate/security.js +167 -0
  64. package/dist_ts_web/appstate/shared.d.ts +3 -0
  65. package/dist_ts_web/appstate/shared.js +13 -0
  66. package/dist_ts_web/appstate/stats.d.ts +15 -0
  67. package/dist_ts_web/appstate/stats.js +59 -0
  68. package/dist_ts_web/appstate/target-profiles.d.ts +37 -0
  69. package/dist_ts_web/appstate/target-profiles.js +118 -0
  70. package/dist_ts_web/appstate/ui.d.ts +11 -0
  71. package/dist_ts_web/appstate/ui.js +55 -0
  72. package/dist_ts_web/appstate/users.d.ts +27 -0
  73. package/dist_ts_web/appstate/users.js +85 -0
  74. package/dist_ts_web/appstate/vpn.d.ts +44 -0
  75. package/dist_ts_web/appstate/vpn.js +148 -0
  76. package/dist_ts_web/appstate.d.ts +20 -568
  77. package/dist_ts_web/appstate.js +24 -2418
  78. package/package.json +1 -1
  79. package/ts/00_commitinfo_data.ts +1 -1
  80. package/ts/acme/classes.smartacme-lifecycle.ts +155 -0
  81. package/ts/acme/index.ts +1 -0
  82. package/ts/classes.dcrouter.ts +118 -1919
  83. package/ts/dns/classes.dns-server-runtime.ts +525 -0
  84. package/ts/dns/index.ts +1 -0
  85. package/ts/email/classes.accepted-email-spool.ts +434 -0
  86. package/ts/email/classes.email-route-builder.ts +312 -0
  87. package/ts/email/index.ts +2 -0
  88. package/ts/opsserver/handlers/gatewayclient.handler.ts +9 -7
  89. package/ts/remoteingress/classes.hub-lifecycle.ts +278 -0
  90. package/ts/remoteingress/classes.remoteingress-manager.ts +1 -1
  91. package/ts/remoteingress/index.ts +1 -0
  92. package/ts/security/classes.route-policy-augmenter.ts +140 -0
  93. package/ts/security/index.ts +1 -0
  94. package/ts/vpn/classes.vpn-access-resolver.ts +126 -0
  95. package/ts/vpn/index.ts +1 -0
  96. package/ts_web/00_commitinfo_data.ts +1 -1
  97. package/ts_web/appstate/acme.ts +93 -0
  98. package/ts_web/appstate/certificates.ts +159 -0
  99. package/ts_web/appstate/config.ts +49 -0
  100. package/ts_web/appstate/domains.ts +429 -0
  101. package/ts_web/appstate/email-domains.ts +155 -0
  102. package/ts_web/appstate/email-ops.ts +57 -0
  103. package/ts_web/appstate/login.ts +128 -0
  104. package/ts_web/appstate/logs.ts +50 -0
  105. package/ts_web/appstate/network.ts +161 -0
  106. package/ts_web/appstate/profiles-targets.ts +240 -0
  107. package/ts_web/appstate/remoteingress.ts +300 -0
  108. package/ts_web/appstate/routes.ts +447 -0
  109. package/ts_web/appstate/runtime.ts +308 -0
  110. package/ts_web/appstate/security.ts +229 -0
  111. package/ts_web/appstate/shared.ts +15 -0
  112. package/ts_web/appstate/stats.ts +79 -0
  113. package/ts_web/appstate/target-profiles.ts +164 -0
  114. package/ts_web/appstate/ui.ts +75 -0
  115. package/ts_web/appstate/users.ts +133 -0
  116. package/ts_web/appstate/vpn.ts +234 -0
  117. package/ts_web/appstate.ts +24 -3403
@@ -0,0 +1,37 @@
1
+ import * as plugins from '../plugins.js';
2
+ import type { DcRouter } from '../classes.dcrouter.js';
3
+ /**
4
+ * Sets up and feeds the embedded authoritative smartdns server: validates the
5
+ * DNS configuration, generates authoritative/email/DKIM records, applies
6
+ * proxy-IP replacement, registers record handlers, wires rate-limited query
7
+ * logging/metrics, and provides the DoH socket handler for SmartProxy routes.
8
+ */
9
+ export declare class DnsServerRuntime {
10
+ private dcRouterRef;
11
+ private logWindowSecond;
12
+ private logWindowCount;
13
+ private batchCount;
14
+ private batchTimer;
15
+ constructor(dcRouterRef: DcRouter);
16
+ /**
17
+ * Create the DNS server, start it on UDP, wire metrics/logging, and
18
+ * register all generated records.
19
+ */
20
+ setup(): Promise<void>;
21
+ /**
22
+ * Create the DoH socket handler SmartProxy routes hand TLS sockets to.
23
+ */
24
+ createSocketHandler(): (socket: plugins.net.Socket) => Promise<void>;
25
+ /** Flush the pending rate-limited query-log batch and reset logging state. */
26
+ flushQueryLogBatch(): void;
27
+ private registerRecords;
28
+ private parseRecordData;
29
+ private validateConfiguration;
30
+ private generateEmailDnsRecords;
31
+ private loadDkimRecords;
32
+ private initializeDkimForEmailDomains;
33
+ private generateAuthoritativeRecords;
34
+ private extractDomain;
35
+ private applyProxyIpReplacement;
36
+ private detectServerPublicIp;
37
+ }
@@ -0,0 +1,449 @@
1
+ import * as plugins from '../plugins.js';
2
+ import * as paths from '../paths.js';
3
+ import { logger } from '../logger.js';
4
+ import { buildEmailDnsRecords } from '../email/index.js';
5
+ /**
6
+ * Sets up and feeds the embedded authoritative smartdns server: validates the
7
+ * DNS configuration, generates authoritative/email/DKIM records, applies
8
+ * proxy-IP replacement, registers record handlers, wires rate-limited query
9
+ * logging/metrics, and provides the DoH socket handler for SmartProxy routes.
10
+ */
11
+ export class DnsServerRuntime {
12
+ dcRouterRef;
13
+ // Adaptive query-log rate limiting state
14
+ logWindowSecond = 0; // epoch second of current window
15
+ logWindowCount = 0; // queries logged this second
16
+ batchCount = 0;
17
+ batchTimer = null;
18
+ constructor(dcRouterRef) {
19
+ this.dcRouterRef = dcRouterRef;
20
+ }
21
+ /**
22
+ * Create the DNS server, start it on UDP, wire metrics/logging, and
23
+ * register all generated records.
24
+ */
25
+ async setup() {
26
+ const options = this.dcRouterRef.options;
27
+ if (!options.dnsNsDomains || options.dnsNsDomains.length === 0) {
28
+ throw new Error('dnsNsDomains is required for DNS server setup');
29
+ }
30
+ if (!options.dnsScopes || options.dnsScopes.length === 0) {
31
+ throw new Error('dnsScopes is required for DNS server setup');
32
+ }
33
+ const primaryNameserver = options.dnsNsDomains[0];
34
+ logger.log('info', `Setting up DNS server with primary nameserver: ${primaryNameserver}`);
35
+ // Get VM IP address for UDP binding
36
+ const networkInterfaces = plugins.os.networkInterfaces();
37
+ let vmIpAddress = options.dnsBindInterface || '0.0.0.0'; // Default to all interfaces
38
+ // Try to find the VM's internal IP address when no explicit bind address is configured.
39
+ if (!options.dnsBindInterface) {
40
+ interfaceLoop: for (const [_name, interfaces] of Object.entries(networkInterfaces)) {
41
+ if (interfaces) {
42
+ for (const iface of interfaces) {
43
+ if (!iface.internal && iface.family === 'IPv4') {
44
+ vmIpAddress = iface.address;
45
+ break interfaceLoop;
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ // Create DNS server instance with manual HTTPS mode
52
+ const dnsServer = new plugins.smartdns.dnsServerMod.DnsServer({
53
+ udpPort: 53,
54
+ udpBindInterface: vmIpAddress,
55
+ httpsPort: 443, // Required but won't bind due to manual mode
56
+ manualHttpsMode: true, // Enable manual HTTPS socket handling
57
+ dnssecZone: primaryNameserver,
58
+ primaryNameserver: primaryNameserver, // Automatically generates correct SOA records
59
+ // For now, use self-signed cert until we integrate with Let's Encrypt
60
+ httpsKey: '',
61
+ httpsCert: ''
62
+ });
63
+ this.dcRouterRef.dnsServer = dnsServer;
64
+ // Start the DNS server (UDP only)
65
+ await dnsServer.start();
66
+ logger.log('info', `DNS server started on UDP ${vmIpAddress}:53`);
67
+ // Wire DNS query events to MetricsManager and logger with adaptive rate limiting
68
+ if (this.dcRouterRef.metricsManager) {
69
+ const flushDnsBatch = () => {
70
+ if (this.batchCount > 0) {
71
+ logger.log('info', `DNS: ${this.batchCount} queries processed (rate limited)`, { zone: 'dns' });
72
+ this.batchCount = 0;
73
+ }
74
+ this.batchTimer = null;
75
+ };
76
+ dnsServer.on('query', (event) => {
77
+ // Metrics tracking
78
+ for (const question of event.questions) {
79
+ this.dcRouterRef.metricsManager?.trackDnsQuery(question.type, question.name, false, event.responseTimeMs, event.answered);
80
+ }
81
+ // Adaptive logging: individual logs up to 2/sec, then batch
82
+ const nowSec = Math.floor(Date.now() / 1000);
83
+ if (nowSec !== this.logWindowSecond) {
84
+ this.logWindowSecond = nowSec;
85
+ this.logWindowCount = 0;
86
+ }
87
+ if (this.logWindowCount < 2) {
88
+ this.logWindowCount++;
89
+ const summary = event.questions.map(q => `${q.type} ${q.name}`).join(', ');
90
+ logger.log('info', `DNS query: ${summary} (${event.responseTimeMs}ms, ${event.answered ? 'answered' : 'unanswered'})`, { zone: 'dns' });
91
+ }
92
+ else {
93
+ this.batchCount++;
94
+ if (!this.batchTimer) {
95
+ this.batchTimer = setTimeout(flushDnsBatch, 5000);
96
+ }
97
+ }
98
+ });
99
+ }
100
+ // Validate DNS configuration
101
+ await this.validateConfiguration();
102
+ // Generate and register authoritative records
103
+ const authoritativeRecords = await this.generateAuthoritativeRecords();
104
+ // Generate email DNS records
105
+ const emailDnsRecords = await this.generateEmailDnsRecords();
106
+ // Ensure DKIM keys exist for internal-dns domains before generating records.
107
+ await this.initializeDkimForEmailDomains();
108
+ // Generate DKIM records directly from smartmta.
109
+ const dkimRecords = await this.loadDkimRecords();
110
+ // Combine all records: authoritative, email, DKIM, and user-defined
111
+ const allRecords = [...authoritativeRecords, ...emailDnsRecords, ...dkimRecords];
112
+ if (options.dnsRecords && options.dnsRecords.length > 0) {
113
+ allRecords.push(...options.dnsRecords);
114
+ }
115
+ // Apply proxy IP replacement if configured
116
+ await this.applyProxyIpReplacement(allRecords);
117
+ // Register all DNS records
118
+ if (allRecords.length > 0) {
119
+ this.registerRecords(allRecords);
120
+ logger.log('info', `Registered ${allRecords.length} DNS records (${authoritativeRecords.length} authoritative, ${emailDnsRecords.length} email, ${dkimRecords.length} DKIM, ${options.dnsRecords?.length || 0} user-defined)`);
121
+ }
122
+ // Hand the DnsServer to DnsManager so DB-backed local records on
123
+ // dcrouter-hosted domains get registered too.
124
+ if (this.dcRouterRef.dnsManager) {
125
+ await this.dcRouterRef.dnsManager.attachDnsServer(dnsServer);
126
+ }
127
+ }
128
+ /**
129
+ * Create the DoH socket handler SmartProxy routes hand TLS sockets to.
130
+ */
131
+ createSocketHandler() {
132
+ return async (socket) => {
133
+ if (!this.dcRouterRef.dnsServer) {
134
+ logger.log('error', 'DNS socket handler called but DNS server not initialized');
135
+ socket.end();
136
+ return;
137
+ }
138
+ // Prevent uncaught exception from socket 'error' events
139
+ socket.on('error', (err) => {
140
+ logger.log('error', `DNS socket error: ${err.message}`);
141
+ if (!socket.destroyed) {
142
+ socket.destroy();
143
+ }
144
+ });
145
+ logger.log('debug', 'DNS socket handler: passing socket to DnsServer');
146
+ try {
147
+ // Use the built-in socket handler from smartdns
148
+ // This handles HTTP/2, DoH protocol, etc.
149
+ await this.dcRouterRef.dnsServer.handleHttpsSocket(socket);
150
+ }
151
+ catch (error) {
152
+ logger.log('error', `DNS socket handler error: ${error.message}`);
153
+ if (!socket.destroyed) {
154
+ socket.destroy();
155
+ }
156
+ }
157
+ };
158
+ }
159
+ /** Flush the pending rate-limited query-log batch and reset logging state. */
160
+ flushQueryLogBatch() {
161
+ if (this.batchTimer) {
162
+ clearTimeout(this.batchTimer);
163
+ if (this.batchCount > 0) {
164
+ logger.log('info', `DNS: ${this.batchCount} queries processed (final flush)`, { zone: 'dns' });
165
+ }
166
+ this.batchTimer = null;
167
+ this.batchCount = 0;
168
+ this.logWindowSecond = 0;
169
+ this.logWindowCount = 0;
170
+ }
171
+ }
172
+ registerRecords(records) {
173
+ const dnsServer = this.dcRouterRef.dnsServer;
174
+ if (!dnsServer)
175
+ return;
176
+ // Register a separate handler for each record
177
+ // This ensures multiple records of the same type (like NS records) are all served
178
+ for (const record of records) {
179
+ // Register handler for this specific record
180
+ dnsServer.registerHandler(record.name, [record.type], (question) => {
181
+ // Check if this handler matches the question
182
+ if (question.name === record.name && question.type === record.type) {
183
+ return {
184
+ name: record.name,
185
+ type: record.type,
186
+ class: 'IN',
187
+ ttl: record.ttl || 300,
188
+ data: this.parseRecordData(record.type, record.value)
189
+ };
190
+ }
191
+ return null;
192
+ });
193
+ }
194
+ logger.log('info', `Registered ${records.length} DNS handlers (one per record)`);
195
+ }
196
+ parseRecordData(type, value) {
197
+ switch (type) {
198
+ case 'A':
199
+ return value; // IP address as string
200
+ case 'MX':
201
+ const [priority, exchange] = value.split(' ');
202
+ return { priority: parseInt(priority), exchange };
203
+ case 'TXT':
204
+ return value;
205
+ case 'NS':
206
+ return value;
207
+ case 'SOA':
208
+ // SOA format: primary-ns admin-email serial refresh retry expire minimum
209
+ const parts = value.split(' ');
210
+ return {
211
+ mname: parts[0],
212
+ rname: parts[1],
213
+ serial: parseInt(parts[2]),
214
+ refresh: parseInt(parts[3]),
215
+ retry: parseInt(parts[4]),
216
+ expire: parseInt(parts[5]),
217
+ minimum: parseInt(parts[6])
218
+ };
219
+ default:
220
+ return value;
221
+ }
222
+ }
223
+ async validateConfiguration() {
224
+ const options = this.dcRouterRef.options;
225
+ if (!options.dnsNsDomains || !options.dnsScopes) {
226
+ return;
227
+ }
228
+ logger.log('info', 'Validating DNS configuration...');
229
+ // Check if email domains with internal-dns are in dnsScopes
230
+ if (options.emailConfig?.domains) {
231
+ for (const domainConfig of options.emailConfig.domains) {
232
+ if (domainConfig.dnsMode === 'internal-dns' &&
233
+ !options.dnsScopes.includes(domainConfig.domain)) {
234
+ logger.log('warn', `Email domain '${domainConfig.domain}' with internal-dns mode is not in dnsScopes. It should be added to dnsScopes.`);
235
+ }
236
+ }
237
+ }
238
+ // Validate user-provided DNS records are within scopes
239
+ if (options.dnsRecords) {
240
+ for (const record of options.dnsRecords) {
241
+ const recordDomain = this.extractDomain(record.name);
242
+ const isInScope = options.dnsScopes.some(scope => recordDomain === scope || recordDomain.endsWith(`.${scope}`));
243
+ if (!isInScope) {
244
+ logger.log('warn', `DNS record for '${record.name}' is outside defined scopes [${options.dnsScopes.join(', ')}]`);
245
+ }
246
+ }
247
+ }
248
+ }
249
+ async generateEmailDnsRecords() {
250
+ const options = this.dcRouterRef.options;
251
+ const records = [];
252
+ if (!options.emailConfig?.domains) {
253
+ return records;
254
+ }
255
+ // Filter domains with internal-dns mode
256
+ const internalDnsDomains = options.emailConfig.domains.filter(domain => domain.dnsMode === 'internal-dns');
257
+ for (const domainConfig of internalDnsDomains) {
258
+ const domain = domainConfig.domain;
259
+ const ttl = domainConfig.dns?.internal?.ttl || 3600;
260
+ const requiredRecords = buildEmailDnsRecords({
261
+ domain,
262
+ hostname: options.emailConfig.hostname,
263
+ mxPriority: domainConfig.dns?.internal?.mxPriority,
264
+ }).filter((record) => !record.name.includes('._domainkey.'));
265
+ for (const record of requiredRecords) {
266
+ records.push({
267
+ name: record.name,
268
+ type: record.type,
269
+ value: record.value,
270
+ ttl,
271
+ });
272
+ }
273
+ }
274
+ logger.log('info', `Generated ${records.length} email DNS records for ${internalDnsDomains.length} internal-dns domains`);
275
+ return records;
276
+ }
277
+ async loadDkimRecords() {
278
+ const options = this.dcRouterRef.options;
279
+ const records = [];
280
+ if (!options.emailConfig?.domains || !this.dcRouterRef.emailServer?.dkimCreator) {
281
+ return records;
282
+ }
283
+ for (const domainConfig of options.emailConfig.domains) {
284
+ if (domainConfig.dnsMode !== 'internal-dns') {
285
+ continue;
286
+ }
287
+ const selector = domainConfig.dkim?.selector || 'default';
288
+ try {
289
+ const dkimRecord = await this.dcRouterRef.emailServer.dkimCreator.getDNSRecordForDomain(domainConfig.domain, selector);
290
+ records.push({
291
+ name: dkimRecord.name,
292
+ type: 'TXT',
293
+ value: dkimRecord.value,
294
+ ttl: domainConfig.dns?.internal?.ttl || 3600,
295
+ });
296
+ }
297
+ catch (error) {
298
+ logger.log('error', `Failed to generate DKIM record for ${domainConfig.domain}: ${error.message}`);
299
+ }
300
+ }
301
+ return records;
302
+ }
303
+ async initializeDkimForEmailDomains() {
304
+ const options = this.dcRouterRef.options;
305
+ if (!options.emailConfig?.domains || !this.dcRouterRef.emailServer) {
306
+ return;
307
+ }
308
+ logger.log('info', 'Initializing DKIM keys for email domains...');
309
+ // Get DKIMCreator instance from email server (public in smartmta)
310
+ const dkimCreator = this.dcRouterRef.emailServer.dkimCreator;
311
+ if (!dkimCreator) {
312
+ logger.log('warn', 'DKIMCreator not available, skipping DKIM initialization');
313
+ return;
314
+ }
315
+ // Ensure necessary directories exist
316
+ paths.ensureDataDirectories(this.dcRouterRef.resolvedPaths);
317
+ // Generate DKIM keys for each internal-dns email domain using the configured selector.
318
+ for (const domainConfig of options.emailConfig.domains) {
319
+ if (domainConfig.dnsMode !== 'internal-dns') {
320
+ continue;
321
+ }
322
+ try {
323
+ await dkimCreator.handleDKIMKeysForSelector(domainConfig.domain, domainConfig.dkim?.selector || 'default', domainConfig.dkim?.keySize || 2048);
324
+ logger.log('info', `DKIM keys initialized for ${domainConfig.domain}`);
325
+ }
326
+ catch (error) {
327
+ logger.log('error', `Failed to initialize DKIM for ${domainConfig.domain}: ${error.message}`);
328
+ }
329
+ }
330
+ logger.log('info', 'DKIM initialization complete');
331
+ }
332
+ async generateAuthoritativeRecords() {
333
+ const options = this.dcRouterRef.options;
334
+ const records = [];
335
+ if (!options.dnsNsDomains || !options.dnsScopes) {
336
+ return records;
337
+ }
338
+ // Determine the public IP for nameserver A records
339
+ let publicIp = null;
340
+ // Use proxy IPs if configured (these should be public IPs)
341
+ if (options.proxyIps && options.proxyIps.length > 0) {
342
+ publicIp = options.proxyIps[0]; // Use first proxy IP
343
+ logger.log('info', `Using proxy IP for nameserver A records: ${publicIp}`);
344
+ }
345
+ else if (options.publicIp) {
346
+ // Use explicitly configured public IP
347
+ publicIp = options.publicIp;
348
+ this.dcRouterRef.detectedPublicIp = publicIp;
349
+ logger.log('info', `Using configured public IP for nameserver A records: ${publicIp}`);
350
+ }
351
+ else {
352
+ // Auto-discover public IP using smartnetwork
353
+ try {
354
+ logger.log('info', 'Auto-discovering public IP address...');
355
+ const smartNetwork = new plugins.smartnetwork.SmartNetwork();
356
+ const publicIps = await smartNetwork.getPublicIps();
357
+ if (publicIps.v4) {
358
+ publicIp = publicIps.v4;
359
+ this.dcRouterRef.detectedPublicIp = publicIp;
360
+ logger.log('info', `Auto-discovered public IPv4: ${publicIp}`);
361
+ }
362
+ else {
363
+ logger.log('warn', 'Could not auto-discover public IPv4 address');
364
+ }
365
+ }
366
+ catch (error) {
367
+ logger.log('error', `Failed to auto-discover public IP: ${error.message}`);
368
+ }
369
+ if (!publicIp) {
370
+ logger.log('warn', 'No public IP available. Nameserver A records require either proxyIps, publicIp, or successful auto-discovery.');
371
+ }
372
+ }
373
+ // Generate A records for nameservers if we have a public IP
374
+ if (publicIp) {
375
+ for (const nsDomain of options.dnsNsDomains) {
376
+ records.push({
377
+ name: nsDomain,
378
+ type: 'A',
379
+ value: publicIp,
380
+ ttl: 3600
381
+ });
382
+ }
383
+ logger.log('info', `Generated A records for ${options.dnsNsDomains.length} nameservers`);
384
+ }
385
+ // Generate NS records for each domain in scopes
386
+ for (const domain of options.dnsScopes) {
387
+ // Add NS records for all nameservers
388
+ for (const nsDomain of options.dnsNsDomains) {
389
+ records.push({
390
+ name: domain,
391
+ type: 'NS',
392
+ value: nsDomain,
393
+ ttl: 3600
394
+ });
395
+ }
396
+ // SOA records are now automatically generated by smartdns DnsServer
397
+ // with the primaryNameserver configuration option
398
+ }
399
+ logger.log('info', `Generated ${records.length} total records (A + NS) for ${options.dnsScopes.length} domains`);
400
+ return records;
401
+ }
402
+ extractDomain(recordName) {
403
+ // Handle wildcards
404
+ if (recordName.startsWith('*.')) {
405
+ recordName = recordName.substring(2);
406
+ }
407
+ return recordName;
408
+ }
409
+ async applyProxyIpReplacement(records) {
410
+ const options = this.dcRouterRef.options;
411
+ if (!options.proxyIps || options.proxyIps.length === 0) {
412
+ return; // No proxy IPs configured, skip replacement
413
+ }
414
+ // Get server's public IP
415
+ const serverIp = await this.detectServerPublicIp();
416
+ if (!serverIp) {
417
+ logger.log('warn', 'Could not detect server public IP, skipping proxy IP replacement');
418
+ return;
419
+ }
420
+ logger.log('info', `Applying proxy IP replacement. Server IP: ${serverIp}, Proxy IPs: ${options.proxyIps.join(', ')}`);
421
+ let proxyIndex = 0;
422
+ for (const record of records) {
423
+ if (record.type === 'A' &&
424
+ record.value === serverIp &&
425
+ record.useIngressProxy !== false) {
426
+ // Round-robin through proxy IPs
427
+ const proxyIp = options.proxyIps[proxyIndex % options.proxyIps.length];
428
+ logger.log('info', `Replacing A record for ${record.name}: ${record.value} → ${proxyIp}`);
429
+ record.value = proxyIp;
430
+ proxyIndex++;
431
+ }
432
+ }
433
+ }
434
+ async detectServerPublicIp() {
435
+ try {
436
+ const smartNetwork = new plugins.smartnetwork.SmartNetwork();
437
+ const publicIps = await smartNetwork.getPublicIps();
438
+ if (publicIps.v4) {
439
+ return publicIps.v4;
440
+ }
441
+ return null;
442
+ }
443
+ catch (error) {
444
+ logger.log('warn', `Failed to detect public IP: ${error.message}`);
445
+ return null;
446
+ }
447
+ }
448
+ }
449
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5kbnMtc2VydmVyLXJ1bnRpbWUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9kbnMvY2xhc3Nlcy5kbnMtc2VydmVyLXJ1bnRpbWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxlQUFlLENBQUM7QUFDekMsT0FBTyxLQUFLLEtBQUssTUFBTSxhQUFhLENBQUM7QUFDckMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN0QyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUt6RDs7Ozs7R0FLRztBQUNILE1BQU0sT0FBTyxnQkFBZ0I7SUFPUDtJQU5wQix5Q0FBeUM7SUFDakMsZUFBZSxHQUFHLENBQUMsQ0FBQyxDQUFDLGlDQUFpQztJQUN0RCxjQUFjLEdBQUcsQ0FBQyxDQUFDLENBQUMsNkJBQTZCO0lBQ2pELFVBQVUsR0FBRyxDQUFDLENBQUM7SUFDZixVQUFVLEdBQXlDLElBQUksQ0FBQztJQUVoRSxZQUFvQixXQUFxQjtRQUFyQixnQkFBVyxHQUFYLFdBQVcsQ0FBVTtJQUFHLENBQUM7SUFFN0M7OztPQUdHO0lBQ0ksS0FBSyxDQUFDLEtBQUs7UUFDaEIsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUM7UUFDekMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxZQUFZLElBQUksT0FBTyxDQUFDLFlBQVksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDL0QsTUFBTSxJQUFJLEtBQUssQ0FBQywrQ0FBK0MsQ0FBQyxDQUFDO1FBQ25FLENBQUM7UUFFRCxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVMsSUFBSSxPQUFPLENBQUMsU0FBUyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN6RCxNQUFNLElBQUksS0FBSyxDQUFDLDRDQUE0QyxDQUFDLENBQUM7UUFDaEUsQ0FBQztR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
@@ -1,2 +1,3 @@
1
1
  export * from './manager.dns.js';
2
2
  export * from './providers/index.js';
3
+ export * from './classes.dns-server-runtime.js';
@@ -1,3 +1,4 @@
1
1
  export * from './manager.dns.js';
2
2
  export * from './providers/index.js';
3
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9kbnMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxrQkFBa0IsQ0FBQztBQUNqQyxjQUFjLHNCQUFzQixDQUFDIn0=
3
+ export * from './classes.dns-server-runtime.js';
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90cy9kbnMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxrQkFBa0IsQ0FBQztBQUNqQyxjQUFjLHNCQUFzQixDQUFDO0FBQ3JDLGNBQWMsaUNBQWlDLENBQUMifQ==
@@ -0,0 +1,55 @@
1
+ import type { IMessageAcceptanceContext, IMessageAcceptanceDecision } from '@push.rocks/smartmta';
2
+ import type { DcRouter } from '../classes.dcrouter.js';
3
+ export declare const DCROUTER_CACHE_ID_HEADER = "X-Dcrouter-Cached-Email-Id";
4
+ export type TSmartMtaQueueItemLike = {
5
+ processingResult?: {
6
+ headers?: Record<string, string>;
7
+ email?: {
8
+ headers?: Record<string, string>;
9
+ };
10
+ };
11
+ status?: 'pending' | 'processing' | 'queued' | 'delivered' | 'failed' | 'deferred';
12
+ attempts?: number;
13
+ nextAttempt?: Date;
14
+ lastError?: string;
15
+ };
16
+ /**
17
+ * Accept-then-spool pipeline for inbound SMTP messages: persists accepted
18
+ * messages as CachedEmail docs, replays them through SmartMTA on an interval,
19
+ * and mirrors SmartMTA delivery-queue outcomes back onto the cached docs.
20
+ */
21
+ export declare class AcceptedEmailSpool {
22
+ private dcRouterRef;
23
+ private spoolTimer?;
24
+ private spoolRun?;
25
+ private processing;
26
+ private stopping;
27
+ private queueUpdatePromises;
28
+ constructor(dcRouterRef: DcRouter);
29
+ acceptMessage(context: IMessageAcceptanceContext, processAfterAccept?: boolean): Promise<IMessageAcceptanceDecision>;
30
+ /** Start the interval-driven spool processor and trigger an immediate run. */
31
+ start(): void;
32
+ /** Mark the spool as stopping and clear the interval without awaiting in-flight work. */
33
+ beginStop(): void;
34
+ /** Stop the spool and wait (bounded) for an in-flight run to settle. */
35
+ stop(): Promise<void>;
36
+ /** Kick off a spool run unless one is already in flight. */
37
+ run(): void;
38
+ trackQueueUpdate(item: TSmartMtaQueueItemLike, status: 'queued' | 'delivered' | 'failed', failureMessage: string): void;
39
+ drainQueueUpdates(): Promise<void>;
40
+ /** Requeue emails left in 'queued' state by a previous process as pending. */
41
+ recoverQueuedEmails(): Promise<void>;
42
+ private processSpool;
43
+ private processAcceptedCachedEmail;
44
+ private buildCachedEmailSession;
45
+ private parseCachedEmailRouteData;
46
+ private updateAcceptedEmailFromQueueItem;
47
+ private waitForPromiseToSettleWithTimeout;
48
+ private clearSpoolTimer;
49
+ private setDcRouterCacheIdHeader;
50
+ private isCachedEmailTerminal;
51
+ private getCachedEmailIdFromQueueItem;
52
+ private getHeaderValue;
53
+ private removeHeader;
54
+ private throwIfMessageAcceptanceAborted;
55
+ }