@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.
- package/deno.json +1 -1
- package/dist_serve/bundle.js +768 -768
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/acme/classes.smartacme-lifecycle.d.ts +25 -0
- package/dist_ts/acme/classes.smartacme-lifecycle.js +144 -0
- package/dist_ts/acme/index.d.ts +1 -0
- package/dist_ts/acme/index.js +2 -1
- package/dist_ts/classes.dcrouter.d.ts +21 -139
- package/dist_ts/classes.dcrouter.js +71 -1585
- package/dist_ts/dns/classes.dns-server-runtime.d.ts +37 -0
- package/dist_ts/dns/classes.dns-server-runtime.js +449 -0
- package/dist_ts/dns/index.d.ts +1 -0
- package/dist_ts/dns/index.js +2 -1
- package/dist_ts/email/classes.accepted-email-spool.d.ts +55 -0
- package/dist_ts/email/classes.accepted-email-spool.js +345 -0
- package/dist_ts/email/classes.email-route-builder.d.ts +28 -0
- package/dist_ts/email/classes.email-route-builder.js +260 -0
- package/dist_ts/email/index.d.ts +2 -0
- package/dist_ts/email/index.js +3 -1
- package/dist_ts/opsserver/handlers/gatewayclient.handler.js +10 -8
- package/dist_ts/remoteingress/classes.hub-lifecycle.d.ts +27 -0
- package/dist_ts/remoteingress/classes.hub-lifecycle.js +241 -0
- package/dist_ts/remoteingress/classes.remoteingress-manager.d.ts +1 -2
- package/dist_ts/remoteingress/index.d.ts +1 -0
- package/dist_ts/remoteingress/index.js +2 -1
- package/dist_ts/security/classes.route-policy-augmenter.d.ts +22 -0
- package/dist_ts/security/classes.route-policy-augmenter.js +120 -0
- package/dist_ts/security/index.d.ts +1 -0
- package/dist_ts/security/index.js +2 -1
- package/dist_ts/vpn/classes.vpn-access-resolver.d.ts +34 -0
- package/dist_ts/vpn/classes.vpn-access-resolver.js +101 -0
- package/dist_ts/vpn/index.d.ts +1 -0
- package/dist_ts/vpn/index.js +2 -1
- package/dist_ts_migrations/index.js +92 -9
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate/acme.d.ts +17 -0
- package/dist_ts_web/appstate/acme.js +64 -0
- package/dist_ts_web/appstate/certificates.d.ts +37 -0
- package/dist_ts_web/appstate/certificates.js +107 -0
- package/dist_ts_web/appstate/config.d.ts +9 -0
- package/dist_ts_web/appstate/config.js +35 -0
- package/dist_ts_web/appstate/domains.d.ts +80 -0
- package/dist_ts_web/appstate/domains.js +324 -0
- package/dist_ts_web/appstate/email-domains.d.ts +25 -0
- package/dist_ts_web/appstate/email-domains.js +104 -0
- package/dist_ts_web/appstate/email-ops.d.ts +10 -0
- package/dist_ts_web/appstate/email-ops.js +40 -0
- package/dist_ts_web/appstate/login.d.ts +30 -0
- package/dist_ts_web/appstate/login.js +83 -0
- package/dist_ts_web/appstate/logs.d.ts +16 -0
- package/dist_ts_web/appstate/logs.js +27 -0
- package/dist_ts_web/appstate/network.d.ts +50 -0
- package/dist_ts_web/appstate/network.js +122 -0
- package/dist_ts_web/appstate/profiles-targets.d.ts +45 -0
- package/dist_ts_web/appstate/profiles-targets.js +173 -0
- package/dist_ts_web/appstate/remoteingress.d.ts +47 -0
- package/dist_ts_web/appstate/remoteingress.js +204 -0
- package/dist_ts_web/appstate/routes.d.ts +76 -0
- package/dist_ts_web/appstate/routes.js +316 -0
- package/dist_ts_web/appstate/runtime.d.ts +1 -0
- package/dist_ts_web/appstate/runtime.js +276 -0
- package/dist_ts_web/appstate/security.d.ts +29 -0
- package/dist_ts_web/appstate/security.js +167 -0
- package/dist_ts_web/appstate/shared.d.ts +3 -0
- package/dist_ts_web/appstate/shared.js +13 -0
- package/dist_ts_web/appstate/stats.d.ts +15 -0
- package/dist_ts_web/appstate/stats.js +59 -0
- package/dist_ts_web/appstate/target-profiles.d.ts +37 -0
- package/dist_ts_web/appstate/target-profiles.js +118 -0
- package/dist_ts_web/appstate/ui.d.ts +11 -0
- package/dist_ts_web/appstate/ui.js +55 -0
- package/dist_ts_web/appstate/users.d.ts +27 -0
- package/dist_ts_web/appstate/users.js +85 -0
- package/dist_ts_web/appstate/vpn.d.ts +44 -0
- package/dist_ts_web/appstate/vpn.js +148 -0
- package/dist_ts_web/appstate.d.ts +20 -568
- package/dist_ts_web/appstate.js +24 -2418
- package/package.json +1 -1
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/acme/classes.smartacme-lifecycle.ts +155 -0
- package/ts/acme/index.ts +1 -0
- package/ts/classes.dcrouter.ts +118 -1919
- package/ts/dns/classes.dns-server-runtime.ts +525 -0
- package/ts/dns/index.ts +1 -0
- package/ts/email/classes.accepted-email-spool.ts +434 -0
- package/ts/email/classes.email-route-builder.ts +312 -0
- package/ts/email/index.ts +2 -0
- package/ts/opsserver/handlers/gatewayclient.handler.ts +9 -7
- package/ts/remoteingress/classes.hub-lifecycle.ts +278 -0
- package/ts/remoteingress/classes.remoteingress-manager.ts +1 -1
- package/ts/remoteingress/index.ts +1 -0
- package/ts/security/classes.route-policy-augmenter.ts +140 -0
- package/ts/security/index.ts +1 -0
- package/ts/vpn/classes.vpn-access-resolver.ts +126 -0
- package/ts/vpn/index.ts +1 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate/acme.ts +93 -0
- package/ts_web/appstate/certificates.ts +159 -0
- package/ts_web/appstate/config.ts +49 -0
- package/ts_web/appstate/domains.ts +429 -0
- package/ts_web/appstate/email-domains.ts +155 -0
- package/ts_web/appstate/email-ops.ts +57 -0
- package/ts_web/appstate/login.ts +128 -0
- package/ts_web/appstate/logs.ts +50 -0
- package/ts_web/appstate/network.ts +161 -0
- package/ts_web/appstate/profiles-targets.ts +240 -0
- package/ts_web/appstate/remoteingress.ts +300 -0
- package/ts_web/appstate/routes.ts +447 -0
- package/ts_web/appstate/runtime.ts +308 -0
- package/ts_web/appstate/security.ts +229 -0
- package/ts_web/appstate/shared.ts +15 -0
- package/ts_web/appstate/stats.ts +79 -0
- package/ts_web/appstate/target-profiles.ts +164 -0
- package/ts_web/appstate/ui.ts +75 -0
- package/ts_web/appstate/users.ts +133 -0
- package/ts_web/appstate/vpn.ts +234 -0
- 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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
|
package/dist_ts/dns/index.d.ts
CHANGED
package/dist_ts/dns/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export * from './manager.dns.js';
|
|
2
2
|
export * from './providers/index.js';
|
|
3
|
-
|
|
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
|
+
}
|