@push.rocks/smartdns 7.5.1 → 7.8.0
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/dist_rust/rustdns-client_linux_amd64 +0 -0
- package/dist_rust/rustdns-client_linux_arm64 +0 -0
- package/dist_rust/rustdns_linux_amd64 +0 -0
- package/dist_rust/rustdns_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts_client/classes.dnsclient.d.ts +20 -31
- package/dist_ts_client/classes.dnsclient.js +126 -44
- package/dist_ts_client/classes.rustdnsclientbridge.d.ts +59 -0
- package/dist_ts_client/classes.rustdnsclientbridge.js +110 -0
- package/dist_ts_client/index.d.ts +1 -0
- package/dist_ts_client/index.js +2 -1
- package/dist_ts_client/plugins.d.ts +8 -1
- package/dist_ts_client/plugins.js +8 -2
- package/dist_ts_server/classes.dnsserver.d.ts +42 -54
- package/dist_ts_server/classes.dnsserver.js +290 -637
- package/dist_ts_server/classes.rustdnsbridge.d.ts +119 -0
- package/dist_ts_server/classes.rustdnsbridge.js +136 -0
- package/dist_ts_server/index.d.ts +1 -0
- package/dist_ts_server/index.js +2 -1
- package/dist_ts_server/plugins.d.ts +8 -7
- package/dist_ts_server/plugins.js +7 -8
- package/npmextra.json +18 -6
- package/package.json +10 -9
- package/readme.hints.md +28 -1
- package/readme.md +345 -645
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/readme.md +47 -0
|
@@ -1,110 +1,167 @@
|
|
|
1
1
|
import * as plugins from './plugins.js';
|
|
2
|
-
import {
|
|
2
|
+
import { RustDnsBridge } from './classes.rustdnsbridge.js';
|
|
3
3
|
import * as dnsPacket from 'dns-packet';
|
|
4
4
|
export class DnsServer {
|
|
5
5
|
constructor(options) {
|
|
6
6
|
this.options = options;
|
|
7
7
|
this.handlers = [];
|
|
8
|
-
// Track
|
|
9
|
-
this.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
this.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
// Track initialization state
|
|
9
|
+
this.bridgeSpawned = false;
|
|
10
|
+
// Legacy server references (kept for backward-compatible test access)
|
|
11
|
+
this.httpsServer = null;
|
|
12
|
+
this.udpServer = null;
|
|
13
|
+
this.bridge = new RustDnsBridge();
|
|
14
|
+
// Wire up the dnsQuery event to run TypeScript handlers
|
|
15
|
+
this.bridge.on('dnsQuery', async (event) => {
|
|
16
|
+
try {
|
|
17
|
+
const answers = this.resolveQuery(event);
|
|
18
|
+
await this.bridge.sendQueryResult(event.correlationId, answers.answers, answers.answered);
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
console.error('Error handling DNS query:', err);
|
|
22
|
+
try {
|
|
23
|
+
await this.bridge.sendQueryResult(event.correlationId, [], false);
|
|
24
|
+
}
|
|
25
|
+
catch (sendErr) {
|
|
26
|
+
console.error('Error sending empty query result:', sendErr);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
17
29
|
});
|
|
18
|
-
// Generate DNSKEY and DS records
|
|
19
|
-
const { dnskeyRecord } = this.dnsSec.getDsAndKeyPair();
|
|
20
|
-
// Parse DNSKEY record into dns-packet format
|
|
21
|
-
this.dnskeyRecord = this.parseDNSKEYRecord(dnskeyRecord);
|
|
22
|
-
this.keyTag = this.computeKeyTag(this.dnskeyRecord);
|
|
23
30
|
}
|
|
24
31
|
/**
|
|
25
|
-
*
|
|
26
|
-
|
|
32
|
+
* Register a DNS handler for a domain pattern and record types.
|
|
33
|
+
*/
|
|
34
|
+
registerHandler(domainPattern, recordTypes, handler) {
|
|
35
|
+
this.handlers.push({ domainPattern, recordTypes, handler });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Unregister a specific handler.
|
|
39
|
+
*/
|
|
40
|
+
unregisterHandler(domainPattern, recordTypes) {
|
|
41
|
+
const initialLength = this.handlers.length;
|
|
42
|
+
this.handlers = this.handlers.filter(handler => !(handler.domainPattern === domainPattern &&
|
|
43
|
+
recordTypes.every(type => handler.recordTypes.includes(type))));
|
|
44
|
+
return this.handlers.length < initialLength;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Start the DNS server.
|
|
48
|
+
*/
|
|
49
|
+
async start() {
|
|
50
|
+
// Validate interface addresses if provided
|
|
51
|
+
const udpInterface = this.options.udpBindInterface || '0.0.0.0';
|
|
52
|
+
const httpsInterface = this.options.httpsBindInterface || '0.0.0.0';
|
|
53
|
+
if (this.options.udpBindInterface && !this.isValidIpAddress(this.options.udpBindInterface)) {
|
|
54
|
+
throw new Error(`Invalid UDP bind interface: ${this.options.udpBindInterface}`);
|
|
55
|
+
}
|
|
56
|
+
if (this.options.httpsBindInterface && !this.isValidIpAddress(this.options.httpsBindInterface)) {
|
|
57
|
+
throw new Error(`Invalid HTTPS bind interface: ${this.options.httpsBindInterface}`);
|
|
58
|
+
}
|
|
59
|
+
// Spawn the Rust binary
|
|
60
|
+
if (!this.bridgeSpawned) {
|
|
61
|
+
const spawned = await this.bridge.spawn();
|
|
62
|
+
if (!spawned) {
|
|
63
|
+
throw new Error('Failed to spawn rustdns binary');
|
|
64
|
+
}
|
|
65
|
+
this.bridgeSpawned = true;
|
|
66
|
+
}
|
|
67
|
+
// Build config for Rust
|
|
68
|
+
const config = {
|
|
69
|
+
udpPort: this.options.udpPort,
|
|
70
|
+
httpsPort: this.options.httpsPort,
|
|
71
|
+
udpBindInterface: udpInterface,
|
|
72
|
+
httpsBindInterface: httpsInterface,
|
|
73
|
+
httpsKey: this.options.httpsKey || '',
|
|
74
|
+
httpsCert: this.options.httpsCert || '',
|
|
75
|
+
dnssecZone: this.options.dnssecZone,
|
|
76
|
+
dnssecAlgorithm: 'ECDSA',
|
|
77
|
+
primaryNameserver: this.options.primaryNameserver || `ns1.${this.options.dnssecZone}`,
|
|
78
|
+
enableLocalhostHandling: this.options.enableLocalhostHandling !== false,
|
|
79
|
+
manualUdpMode: this.options.manualUdpMode || false,
|
|
80
|
+
manualHttpsMode: this.options.manualHttpsMode || false,
|
|
81
|
+
};
|
|
82
|
+
await this.bridge.startServer(config);
|
|
83
|
+
// Set legacy markers for backward-compatible test checks
|
|
84
|
+
this.httpsServer = { _rustBridgeManaged: true };
|
|
85
|
+
this.udpServer = { _rustBridgeManaged: true };
|
|
86
|
+
const udpManual = this.options.manualUdpMode || false;
|
|
87
|
+
const httpsManual = this.options.manualHttpsMode || false;
|
|
88
|
+
if (udpManual && httpsManual) {
|
|
89
|
+
console.log('DNS server started in full manual mode - ready to accept connections');
|
|
90
|
+
}
|
|
91
|
+
else if (udpManual && !httpsManual) {
|
|
92
|
+
console.log('DNS server started with manual UDP mode and automatic HTTPS binding');
|
|
93
|
+
}
|
|
94
|
+
else if (!udpManual && httpsManual) {
|
|
95
|
+
console.log('DNS server started with automatic UDP binding and manual HTTPS mode');
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
console.log(`DNS server started (UDP: ${udpInterface}:${this.options.udpPort}, HTTPS: ${httpsInterface}:${this.options.httpsPort})`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Stop the DNS server.
|
|
103
|
+
*/
|
|
104
|
+
async stop() {
|
|
105
|
+
if (this.bridgeSpawned) {
|
|
106
|
+
try {
|
|
107
|
+
await this.bridge.stopServer();
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
// Ignore errors during stop (process may have already exited)
|
|
111
|
+
}
|
|
112
|
+
this.bridge.kill();
|
|
113
|
+
this.bridgeSpawned = false;
|
|
114
|
+
}
|
|
115
|
+
this.httpsServer = null;
|
|
116
|
+
this.udpServer = null;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Initialize servers (no-op with Rust bridge, kept for API compatibility).
|
|
27
120
|
*/
|
|
28
121
|
initializeServers() {
|
|
29
|
-
|
|
30
|
-
this.initializeHttpsServer();
|
|
122
|
+
// No-op — Rust bridge handles server initialization via start()
|
|
31
123
|
}
|
|
32
124
|
/**
|
|
33
|
-
* Initialize UDP server
|
|
125
|
+
* Initialize UDP server (no-op with Rust bridge).
|
|
34
126
|
*/
|
|
35
127
|
initializeUdpServer() {
|
|
36
|
-
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
// Create UDP socket without binding
|
|
40
|
-
const udpInterface = this.options.udpBindInterface || '0.0.0.0';
|
|
41
|
-
const socketType = this.isIPv6(udpInterface) ? 'udp6' : 'udp4';
|
|
42
|
-
this.udpServer = plugins.dgram.createSocket(socketType);
|
|
43
|
-
// Set up UDP message handler
|
|
44
|
-
this.udpServer.on('message', (msg, rinfo) => {
|
|
45
|
-
this.handleUdpMessage(msg, rinfo);
|
|
46
|
-
});
|
|
47
|
-
this.udpServer.on('error', (err) => {
|
|
48
|
-
console.error(`UDP Server error:\n${err.stack}`);
|
|
49
|
-
this.udpServer.close();
|
|
50
|
-
});
|
|
51
|
-
this.udpServerInitialized = true;
|
|
128
|
+
// No-op
|
|
52
129
|
}
|
|
53
130
|
/**
|
|
54
|
-
* Initialize HTTPS server
|
|
131
|
+
* Initialize HTTPS server (no-op with Rust bridge).
|
|
55
132
|
*/
|
|
56
133
|
initializeHttpsServer() {
|
|
57
|
-
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
// Create HTTPS server without listening
|
|
61
|
-
this.httpsServer = plugins.https.createServer({
|
|
62
|
-
key: this.options.httpsKey,
|
|
63
|
-
cert: this.options.httpsCert,
|
|
64
|
-
}, this.handleHttpsRequest.bind(this));
|
|
65
|
-
this.httpsServerInitialized = true;
|
|
134
|
+
// No-op
|
|
66
135
|
}
|
|
67
136
|
/**
|
|
68
|
-
* Handle a raw TCP socket for HTTPS/DoH
|
|
69
|
-
*
|
|
137
|
+
* Handle a raw TCP socket for HTTPS/DoH.
|
|
138
|
+
* In Rust mode, this is not directly supported — use processRawDnsPacket instead.
|
|
70
139
|
*/
|
|
71
140
|
handleHttpsSocket(socket) {
|
|
72
|
-
|
|
73
|
-
this.initializeHttpsServer();
|
|
74
|
-
}
|
|
75
|
-
// Emit connection event on the HTTPS server
|
|
76
|
-
this.httpsServer.emit('connection', socket);
|
|
141
|
+
console.warn('handleHttpsSocket: direct socket handling not available with Rust bridge. Use processRawDnsPacket instead.');
|
|
77
142
|
}
|
|
78
143
|
/**
|
|
79
|
-
* Handle a UDP message manually
|
|
80
|
-
* @param msg The DNS message buffer
|
|
81
|
-
* @param rinfo Remote address information
|
|
82
|
-
* @param responseCallback Optional callback to handle the response
|
|
144
|
+
* Handle a UDP message manually.
|
|
83
145
|
*/
|
|
84
146
|
handleUdpMessage(msg, rinfo, responseCallback) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const responseData = dnsPacket.encode(response);
|
|
147
|
+
// Async processing via Rust bridge
|
|
148
|
+
this.processRawDnsPacketAsync(msg)
|
|
149
|
+
.then((responseData) => {
|
|
89
150
|
if (responseCallback) {
|
|
90
|
-
// Use custom callback if provided
|
|
91
151
|
responseCallback(responseData, rinfo);
|
|
92
152
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
this.udpServer.send(responseData, rinfo.port, rinfo.address);
|
|
96
|
-
}
|
|
97
|
-
// In manual mode without callback, caller is responsible for sending response
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
153
|
+
})
|
|
154
|
+
.catch((err) => {
|
|
100
155
|
console.error('Error processing UDP DNS request:', err);
|
|
101
|
-
}
|
|
156
|
+
});
|
|
102
157
|
}
|
|
103
158
|
/**
|
|
104
|
-
* Process a raw DNS packet and return the response
|
|
105
|
-
*
|
|
159
|
+
* Process a raw DNS packet and return the response.
|
|
160
|
+
* Synchronous version using the TypeScript fallback (for backward compatibility).
|
|
106
161
|
*/
|
|
107
162
|
processRawDnsPacket(packet) {
|
|
163
|
+
// Synchronous fallback — process locally using TypeScript handler logic
|
|
164
|
+
// This is needed for backward-compatible callers that expect sync results
|
|
108
165
|
try {
|
|
109
166
|
const request = dnsPacket.decode(packet);
|
|
110
167
|
const response = this.processDnsRequest(request);
|
|
@@ -115,34 +172,131 @@ export class DnsServer {
|
|
|
115
172
|
throw err;
|
|
116
173
|
}
|
|
117
174
|
}
|
|
118
|
-
|
|
119
|
-
|
|
175
|
+
/**
|
|
176
|
+
* Process a raw DNS packet asynchronously via Rust bridge.
|
|
177
|
+
*/
|
|
178
|
+
async processRawDnsPacketAsync(packet) {
|
|
179
|
+
if (this.bridgeSpawned) {
|
|
180
|
+
return this.bridge.processPacket(packet);
|
|
181
|
+
}
|
|
182
|
+
// Fallback to local processing if bridge not spawned
|
|
183
|
+
return this.processRawDnsPacket(packet);
|
|
120
184
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
185
|
+
/**
|
|
186
|
+
* Process a DNS request locally (TypeScript handler resolution).
|
|
187
|
+
* Used as fallback and for pre-bridge-spawn calls.
|
|
188
|
+
*/
|
|
189
|
+
processDnsRequest(request) {
|
|
190
|
+
const response = {
|
|
191
|
+
type: 'response',
|
|
192
|
+
id: request.id,
|
|
193
|
+
flags: dnsPacket.AUTHORITATIVE_ANSWER |
|
|
194
|
+
dnsPacket.RECURSION_AVAILABLE |
|
|
195
|
+
(request.flags & dnsPacket.RECURSION_DESIRED ? dnsPacket.RECURSION_DESIRED : 0),
|
|
196
|
+
questions: request.questions,
|
|
197
|
+
answers: [],
|
|
198
|
+
additionals: [],
|
|
199
|
+
};
|
|
200
|
+
for (const question of request.questions) {
|
|
201
|
+
let answered = false;
|
|
202
|
+
const recordsForQuestion = [];
|
|
203
|
+
// Built-in handling for localhost and reverse localhost (RFC 6761)
|
|
204
|
+
const enableLocal = this.options.enableLocalhostHandling !== false;
|
|
205
|
+
if (enableLocal) {
|
|
206
|
+
const qnameLower = (question.name || '').toLowerCase();
|
|
207
|
+
const qnameTrimmed = qnameLower.endsWith('.') ? qnameLower.slice(0, -1) : qnameLower;
|
|
208
|
+
if (qnameTrimmed === 'localhost') {
|
|
209
|
+
if (question.type === 'A') {
|
|
210
|
+
recordsForQuestion.push({
|
|
211
|
+
name: question.name,
|
|
212
|
+
type: 'A',
|
|
213
|
+
class: 'IN',
|
|
214
|
+
ttl: 0,
|
|
215
|
+
data: '127.0.0.1',
|
|
216
|
+
});
|
|
217
|
+
answered = true;
|
|
218
|
+
}
|
|
219
|
+
else if (question.type === 'AAAA') {
|
|
220
|
+
recordsForQuestion.push({
|
|
221
|
+
name: question.name,
|
|
222
|
+
type: 'AAAA',
|
|
223
|
+
class: 'IN',
|
|
224
|
+
ttl: 0,
|
|
225
|
+
data: '::1',
|
|
226
|
+
});
|
|
227
|
+
answered = true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (!answered) {
|
|
231
|
+
const reverseLocalhostV4 = '1.0.0.127.in-addr.arpa';
|
|
232
|
+
if (qnameTrimmed === reverseLocalhostV4 && question.type === 'PTR') {
|
|
233
|
+
recordsForQuestion.push({
|
|
234
|
+
name: question.name,
|
|
235
|
+
type: 'PTR',
|
|
236
|
+
class: 'IN',
|
|
237
|
+
ttl: 0,
|
|
238
|
+
data: 'localhost.',
|
|
239
|
+
});
|
|
240
|
+
answered = true;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Collect all matching records from handlers
|
|
245
|
+
if (!answered) {
|
|
246
|
+
for (const handlerEntry of this.handlers) {
|
|
247
|
+
if (plugins.minimatch.minimatch(question.name, handlerEntry.domainPattern) &&
|
|
248
|
+
handlerEntry.recordTypes.includes(question.type)) {
|
|
249
|
+
const answer = handlerEntry.handler(question);
|
|
250
|
+
if (answer) {
|
|
251
|
+
const dnsAnswer = {
|
|
252
|
+
...answer,
|
|
253
|
+
ttl: answer.ttl || 300,
|
|
254
|
+
class: answer.class || 'IN',
|
|
255
|
+
};
|
|
256
|
+
recordsForQuestion.push(dnsAnswer);
|
|
257
|
+
answered = true;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (recordsForQuestion.length > 0) {
|
|
263
|
+
for (const record of recordsForQuestion) {
|
|
264
|
+
response.answers.push(record);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (!answered) {
|
|
268
|
+
const soaAnswer = {
|
|
269
|
+
name: question.name,
|
|
270
|
+
type: 'SOA',
|
|
271
|
+
class: 'IN',
|
|
272
|
+
ttl: 3600,
|
|
273
|
+
data: {
|
|
274
|
+
mname: this.options.primaryNameserver || `ns1.${this.options.dnssecZone}`,
|
|
275
|
+
rname: `hostmaster.${this.options.dnssecZone}`,
|
|
276
|
+
serial: Math.floor(Date.now() / 1000),
|
|
277
|
+
refresh: 3600,
|
|
278
|
+
retry: 600,
|
|
279
|
+
expire: 604800,
|
|
280
|
+
minimum: 86400,
|
|
281
|
+
},
|
|
282
|
+
};
|
|
283
|
+
response.answers.push(soaAnswer);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return response;
|
|
127
287
|
}
|
|
128
288
|
/**
|
|
129
289
|
* Retrieve SSL certificate for specified domains using Let's Encrypt
|
|
130
|
-
* @param domainNames Array of domain names to include in the certificate
|
|
131
|
-
* @param options Configuration options for Let's Encrypt
|
|
132
|
-
* @returns Object containing certificate, private key, and success status
|
|
133
290
|
*/
|
|
134
291
|
async retrieveSslCertificate(domainNames, options = {}) {
|
|
135
|
-
// Default options
|
|
136
292
|
const opts = {
|
|
137
293
|
email: options.email || 'admin@example.com',
|
|
138
294
|
staging: options.staging !== undefined ? options.staging : false,
|
|
139
295
|
certDir: options.certDir || './certs'
|
|
140
296
|
};
|
|
141
|
-
// Create certificate directory if it doesn't exist
|
|
142
297
|
if (!plugins.fs.existsSync(opts.certDir)) {
|
|
143
298
|
plugins.fs.mkdirSync(opts.certDir, { recursive: true });
|
|
144
299
|
}
|
|
145
|
-
// Filter domains this server is authoritative for
|
|
146
300
|
const authorizedDomains = this.filterAuthorizedDomains(domainNames);
|
|
147
301
|
if (authorizedDomains.length === 0) {
|
|
148
302
|
console.error('None of the provided domains are authorized for this DNS server');
|
|
@@ -150,17 +304,14 @@ export class DnsServer {
|
|
|
150
304
|
}
|
|
151
305
|
console.log(`Retrieving SSL certificate for domains: ${authorizedDomains.join(', ')}`);
|
|
152
306
|
try {
|
|
153
|
-
// Allow for override in tests
|
|
154
307
|
// @ts-ignore - acmeClientOverride is added for testing purposes
|
|
155
308
|
const acmeClient = this.acmeClientOverride || await import('acme-client');
|
|
156
|
-
// Generate or load account key
|
|
157
309
|
const accountKeyPath = plugins.path.join(opts.certDir, 'account.key');
|
|
158
310
|
let accountKey;
|
|
159
311
|
if (plugins.fs.existsSync(accountKeyPath)) {
|
|
160
312
|
accountKey = plugins.fs.readFileSync(accountKeyPath);
|
|
161
313
|
}
|
|
162
314
|
else {
|
|
163
|
-
// Generate new account key
|
|
164
315
|
const { privateKey } = plugins.crypto.generateKeyPairSync('rsa', {
|
|
165
316
|
modulusLength: 2048,
|
|
166
317
|
publicKeyEncoding: { type: 'spki', format: 'pem' },
|
|
@@ -169,44 +320,34 @@ export class DnsServer {
|
|
|
169
320
|
accountKey = Buffer.from(privateKey);
|
|
170
321
|
plugins.fs.writeFileSync(accountKeyPath, accountKey);
|
|
171
322
|
}
|
|
172
|
-
// Initialize ACME client
|
|
173
323
|
const client = new acmeClient.Client({
|
|
174
324
|
directoryUrl: opts.staging
|
|
175
325
|
? acmeClient.directory.letsencrypt.staging
|
|
176
326
|
: acmeClient.directory.letsencrypt.production,
|
|
177
327
|
accountKey: accountKey
|
|
178
328
|
});
|
|
179
|
-
// Create or update account
|
|
180
329
|
await client.createAccount({
|
|
181
330
|
termsOfServiceAgreed: true,
|
|
182
331
|
contact: [`mailto:${opts.email}`]
|
|
183
332
|
});
|
|
184
|
-
// Create order for certificate
|
|
185
333
|
const order = await client.createOrder({
|
|
186
334
|
identifiers: authorizedDomains.map(domain => ({
|
|
187
335
|
type: 'dns',
|
|
188
336
|
value: domain
|
|
189
337
|
}))
|
|
190
338
|
});
|
|
191
|
-
// Get authorizations
|
|
192
339
|
const authorizations = await client.getAuthorizations(order);
|
|
193
|
-
// Track handlers to clean up later
|
|
194
340
|
const challengeHandlers = [];
|
|
195
|
-
// Process each authorization
|
|
196
341
|
for (const auth of authorizations) {
|
|
197
342
|
const domain = auth.identifier.value;
|
|
198
|
-
// Get DNS challenge
|
|
199
343
|
const challenge = auth.challenges.find((c) => c.type === 'dns-01');
|
|
200
344
|
if (!challenge) {
|
|
201
345
|
throw new Error(`No DNS-01 challenge found for ${domain}`);
|
|
202
346
|
}
|
|
203
|
-
// Get key authorization and DNS record value
|
|
204
347
|
const keyAuthorization = await client.getChallengeKeyAuthorization(challenge);
|
|
205
348
|
const recordValue = this.getDnsRecordValueForChallenge(keyAuthorization);
|
|
206
|
-
// Create challenge domain (where TXT record should be placed)
|
|
207
349
|
const challengeDomain = `_acme-challenge.${domain}`;
|
|
208
350
|
console.log(`Setting up TXT record for ${challengeDomain}: ${recordValue}`);
|
|
209
|
-
// Register handler for the TXT record
|
|
210
351
|
this.registerHandler(challengeDomain, ['TXT'], (question) => {
|
|
211
352
|
if (question.name === challengeDomain && question.type === 'TXT') {
|
|
212
353
|
return {
|
|
@@ -219,17 +360,12 @@ export class DnsServer {
|
|
|
219
360
|
}
|
|
220
361
|
return null;
|
|
221
362
|
});
|
|
222
|
-
// Track the handler for cleanup
|
|
223
363
|
challengeHandlers.push({ domain, pattern: challengeDomain });
|
|
224
|
-
// Wait briefly for DNS propagation
|
|
225
364
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
226
|
-
// Complete the challenge
|
|
227
365
|
await client.completeChallenge(challenge);
|
|
228
|
-
// Wait for verification
|
|
229
366
|
await client.waitForValidStatus(challenge);
|
|
230
367
|
console.log(`Challenge for ${domain} validated successfully!`);
|
|
231
368
|
}
|
|
232
|
-
// Generate certificate key
|
|
233
369
|
const domainKeyPath = plugins.path.join(opts.certDir, `${authorizedDomains[0]}.key`);
|
|
234
370
|
const { privateKey } = plugins.crypto.generateKeyPairSync('rsa', {
|
|
235
371
|
modulusLength: 2048,
|
|
@@ -237,26 +373,25 @@ export class DnsServer {
|
|
|
237
373
|
privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
|
|
238
374
|
});
|
|
239
375
|
plugins.fs.writeFileSync(domainKeyPath, privateKey);
|
|
240
|
-
// Use the forge.createCsr method and handle typing with a more direct approach
|
|
241
376
|
const csrResult = await acmeClient.forge.createCsr({
|
|
242
377
|
commonName: authorizedDomains[0],
|
|
243
378
|
altNames: authorizedDomains
|
|
244
379
|
});
|
|
245
|
-
// Finalize the order with the CSR
|
|
246
380
|
await client.finalizeOrder(order, csrResult.csr);
|
|
247
|
-
// Get certificate
|
|
248
381
|
const certificate = await client.getCertificate(order);
|
|
249
|
-
// Save certificate
|
|
250
382
|
const certPath = plugins.path.join(opts.certDir, `${authorizedDomains[0]}.cert`);
|
|
251
383
|
plugins.fs.writeFileSync(certPath, certificate);
|
|
252
|
-
// Update HTTPS server with new certificate
|
|
253
384
|
this.options.httpsCert = certificate;
|
|
254
385
|
this.options.httpsKey = privateKey;
|
|
255
|
-
//
|
|
256
|
-
if (
|
|
257
|
-
|
|
386
|
+
// Update certs on Rust bridge if running
|
|
387
|
+
if (this.bridgeSpawned) {
|
|
388
|
+
try {
|
|
389
|
+
await this.bridge.updateCerts(privateKey, certificate);
|
|
390
|
+
}
|
|
391
|
+
catch (err) {
|
|
392
|
+
console.error('Error updating certs on Rust bridge:', err);
|
|
393
|
+
}
|
|
258
394
|
}
|
|
259
|
-
// Clean up challenge handlers
|
|
260
395
|
for (const handler of challengeHandlers) {
|
|
261
396
|
this.unregisterHandler(handler.pattern, ['TXT']);
|
|
262
397
|
console.log(`Cleaned up challenge handler for ${handler.domain}`);
|
|
@@ -273,562 +408,80 @@ export class DnsServer {
|
|
|
273
408
|
}
|
|
274
409
|
}
|
|
275
410
|
/**
|
|
276
|
-
*
|
|
277
|
-
*/
|
|
278
|
-
getDnsRecordValueForChallenge(keyAuthorization) {
|
|
279
|
-
// Create SHA-256 digest of the key authorization
|
|
280
|
-
const digest = plugins.crypto
|
|
281
|
-
.createHash('sha256')
|
|
282
|
-
.update(keyAuthorization)
|
|
283
|
-
.digest('base64')
|
|
284
|
-
.replace(/\+/g, '-')
|
|
285
|
-
.replace(/\//g, '_')
|
|
286
|
-
.replace(/=/g, '');
|
|
287
|
-
return digest;
|
|
288
|
-
}
|
|
289
|
-
/**
|
|
290
|
-
* Restart the HTTPS server with the new certificate
|
|
291
|
-
*/
|
|
292
|
-
async restartHttpsServer() {
|
|
293
|
-
return new Promise((resolve, reject) => {
|
|
294
|
-
// First check if the server exists
|
|
295
|
-
if (!this.httpsServer) {
|
|
296
|
-
console.log('No HTTPS server to restart');
|
|
297
|
-
resolve();
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
this.httpsServer.close(() => {
|
|
301
|
-
try {
|
|
302
|
-
// Validate certificate and key before trying to create the server
|
|
303
|
-
if (!this.options.httpsCert || !this.options.httpsKey) {
|
|
304
|
-
throw new Error('Missing certificate or key for HTTPS server');
|
|
305
|
-
}
|
|
306
|
-
// For testing, check if we have a mock certificate
|
|
307
|
-
if (this.options.httpsCert.includes('MOCK_CERTIFICATE')) {
|
|
308
|
-
console.log('Using mock certificate in test mode');
|
|
309
|
-
// In test mode with mock cert, we can use the original cert
|
|
310
|
-
// @ts-ignore - accessing acmeClientOverride for testing
|
|
311
|
-
if (this.acmeClientOverride) {
|
|
312
|
-
this.httpsServer = plugins.https.createServer({
|
|
313
|
-
key: this.options.httpsKey,
|
|
314
|
-
cert: this.options.httpsCert,
|
|
315
|
-
}, this.handleHttpsRequest.bind(this));
|
|
316
|
-
if (!this.options.manualHttpsMode) {
|
|
317
|
-
const httpsInterface = this.options.httpsBindInterface || '0.0.0.0';
|
|
318
|
-
this.httpsServer.listen(this.options.httpsPort, httpsInterface, () => {
|
|
319
|
-
console.log(`HTTPS DNS server restarted on ${httpsInterface}:${this.options.httpsPort} with test certificate`);
|
|
320
|
-
resolve();
|
|
321
|
-
});
|
|
322
|
-
}
|
|
323
|
-
else {
|
|
324
|
-
resolve();
|
|
325
|
-
}
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
// Create the new server with the updated certificate
|
|
330
|
-
this.httpsServer = plugins.https.createServer({
|
|
331
|
-
key: this.options.httpsKey,
|
|
332
|
-
cert: this.options.httpsCert,
|
|
333
|
-
}, this.handleHttpsRequest.bind(this));
|
|
334
|
-
if (!this.options.manualHttpsMode) {
|
|
335
|
-
const httpsInterface = this.options.httpsBindInterface || '0.0.0.0';
|
|
336
|
-
this.httpsServer.listen(this.options.httpsPort, httpsInterface, () => {
|
|
337
|
-
console.log(`HTTPS DNS server restarted on ${httpsInterface}:${this.options.httpsPort} with new certificate`);
|
|
338
|
-
resolve();
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
resolve();
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
catch (err) {
|
|
346
|
-
console.error('Error creating HTTPS server with new certificate:', err);
|
|
347
|
-
reject(err);
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
});
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Filter domains to include only those the server is authoritative for
|
|
411
|
+
* Filter domains to include only those the server is authoritative for.
|
|
354
412
|
*/
|
|
355
413
|
filterAuthorizedDomains(domainNames) {
|
|
356
414
|
const authorizedDomains = [];
|
|
357
415
|
for (const domain of domainNames) {
|
|
358
|
-
// Handle wildcards (*.example.com)
|
|
359
416
|
if (domain.startsWith('*.')) {
|
|
360
417
|
const baseDomain = domain.substring(2);
|
|
361
418
|
if (this.isAuthorizedForDomain(baseDomain)) {
|
|
362
419
|
authorizedDomains.push(domain);
|
|
363
420
|
}
|
|
364
421
|
}
|
|
365
|
-
// Regular domains
|
|
366
422
|
else if (this.isAuthorizedForDomain(domain)) {
|
|
367
423
|
authorizedDomains.push(domain);
|
|
368
424
|
}
|
|
369
425
|
}
|
|
370
426
|
return authorizedDomains;
|
|
371
427
|
}
|
|
428
|
+
// ── Private helpers ───────────────────────────────────────────────
|
|
372
429
|
/**
|
|
373
|
-
*
|
|
430
|
+
* Resolve a DNS query event from Rust using TypeScript handlers.
|
|
374
431
|
*/
|
|
432
|
+
resolveQuery(event) {
|
|
433
|
+
const answers = [];
|
|
434
|
+
let answered = false;
|
|
435
|
+
for (const q of event.questions) {
|
|
436
|
+
const question = {
|
|
437
|
+
name: q.name,
|
|
438
|
+
type: q.type,
|
|
439
|
+
class: q.class,
|
|
440
|
+
};
|
|
441
|
+
for (const handlerEntry of this.handlers) {
|
|
442
|
+
if (plugins.minimatch.minimatch(q.name, handlerEntry.domainPattern) &&
|
|
443
|
+
handlerEntry.recordTypes.includes(q.type)) {
|
|
444
|
+
const answer = handlerEntry.handler(question);
|
|
445
|
+
if (answer) {
|
|
446
|
+
answers.push({
|
|
447
|
+
name: answer.name,
|
|
448
|
+
type: answer.type,
|
|
449
|
+
class: typeof answer.class === 'number' ? 'IN' : (answer.class || 'IN'),
|
|
450
|
+
ttl: answer.ttl || 300,
|
|
451
|
+
data: answer.data,
|
|
452
|
+
});
|
|
453
|
+
answered = true;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return { answers, answered };
|
|
459
|
+
}
|
|
460
|
+
getDnsRecordValueForChallenge(keyAuthorization) {
|
|
461
|
+
const digest = plugins.crypto
|
|
462
|
+
.createHash('sha256')
|
|
463
|
+
.update(keyAuthorization)
|
|
464
|
+
.digest('base64')
|
|
465
|
+
.replace(/\+/g, '-')
|
|
466
|
+
.replace(/\//g, '_')
|
|
467
|
+
.replace(/=/g, '');
|
|
468
|
+
return digest;
|
|
469
|
+
}
|
|
375
470
|
isValidIpAddress(ip) {
|
|
376
|
-
// IPv4 pattern
|
|
377
471
|
const ipv4Pattern = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
|
378
|
-
// IPv6 pattern (simplified but more comprehensive)
|
|
379
472
|
const ipv6Pattern = /^(::1|::)$|^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
|
|
380
473
|
return ipv4Pattern.test(ip) || ipv6Pattern.test(ip);
|
|
381
474
|
}
|
|
382
|
-
/**
|
|
383
|
-
* Determine if an IP address is IPv6
|
|
384
|
-
*/
|
|
385
|
-
isIPv6(ip) {
|
|
386
|
-
return ip.includes(':');
|
|
387
|
-
}
|
|
388
|
-
/**
|
|
389
|
-
* Check if the server is authoritative for a domain
|
|
390
|
-
*/
|
|
391
475
|
isAuthorizedForDomain(domain) {
|
|
392
|
-
// Check if any handler matches this domain
|
|
393
476
|
for (const handler of this.handlers) {
|
|
394
477
|
if (plugins.minimatch.minimatch(domain, handler.domainPattern)) {
|
|
395
478
|
return true;
|
|
396
479
|
}
|
|
397
480
|
}
|
|
398
|
-
// Also check if the domain is the DNSSEC zone itself
|
|
399
481
|
if (domain === this.options.dnssecZone || domain.endsWith(`.${this.options.dnssecZone}`)) {
|
|
400
482
|
return true;
|
|
401
483
|
}
|
|
402
484
|
return false;
|
|
403
485
|
}
|
|
404
|
-
processDnsRequest(request) {
|
|
405
|
-
const response = {
|
|
406
|
-
type: 'response',
|
|
407
|
-
id: request.id,
|
|
408
|
-
flags: dnsPacket.AUTHORITATIVE_ANSWER |
|
|
409
|
-
dnsPacket.RECURSION_AVAILABLE |
|
|
410
|
-
(request.flags & dnsPacket.RECURSION_DESIRED ? dnsPacket.RECURSION_DESIRED : 0),
|
|
411
|
-
questions: request.questions,
|
|
412
|
-
answers: [],
|
|
413
|
-
additionals: [],
|
|
414
|
-
};
|
|
415
|
-
const dnssecRequested = this.isDnssecRequested(request);
|
|
416
|
-
// Map to group records by type for proper DNSSEC RRset signing
|
|
417
|
-
const rrsetMap = new Map();
|
|
418
|
-
for (const question of request.questions) {
|
|
419
|
-
console.log(`Query for ${question.name} of type ${question.type}`);
|
|
420
|
-
let answered = false;
|
|
421
|
-
const recordsForQuestion = [];
|
|
422
|
-
// Handle DNSKEY queries if DNSSEC is requested
|
|
423
|
-
if (dnssecRequested && question.type === 'DNSKEY' && question.name === this.options.dnssecZone) {
|
|
424
|
-
const dnskeyAnswer = {
|
|
425
|
-
name: question.name,
|
|
426
|
-
type: 'DNSKEY',
|
|
427
|
-
class: 'IN',
|
|
428
|
-
ttl: 3600,
|
|
429
|
-
data: this.dnskeyRecord,
|
|
430
|
-
};
|
|
431
|
-
recordsForQuestion.push(dnskeyAnswer);
|
|
432
|
-
answered = true;
|
|
433
|
-
}
|
|
434
|
-
else {
|
|
435
|
-
// Collect all matching records from handlers
|
|
436
|
-
for (const handlerEntry of this.handlers) {
|
|
437
|
-
if (plugins.minimatch.minimatch(question.name, handlerEntry.domainPattern) &&
|
|
438
|
-
handlerEntry.recordTypes.includes(question.type)) {
|
|
439
|
-
const answer = handlerEntry.handler(question);
|
|
440
|
-
if (answer) {
|
|
441
|
-
// Ensure the answer has ttl and class
|
|
442
|
-
const dnsAnswer = {
|
|
443
|
-
...answer,
|
|
444
|
-
ttl: answer.ttl || 300,
|
|
445
|
-
class: answer.class || 'IN',
|
|
446
|
-
};
|
|
447
|
-
recordsForQuestion.push(dnsAnswer);
|
|
448
|
-
answered = true;
|
|
449
|
-
// Continue processing other handlers to allow multiple records
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
// Add records to response and group by type for DNSSEC
|
|
455
|
-
if (recordsForQuestion.length > 0) {
|
|
456
|
-
for (const record of recordsForQuestion) {
|
|
457
|
-
response.answers.push(record);
|
|
458
|
-
}
|
|
459
|
-
// Group records by type for DNSSEC signing
|
|
460
|
-
if (dnssecRequested) {
|
|
461
|
-
const rrsetKey = `${question.name}:${question.type}`;
|
|
462
|
-
rrsetMap.set(rrsetKey, recordsForQuestion);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
if (!answered) {
|
|
466
|
-
console.log(`No handler found for ${question.name} of type ${question.type}`);
|
|
467
|
-
response.flags |= dnsPacket.AUTHORITATIVE_ANSWER;
|
|
468
|
-
const soaAnswer = {
|
|
469
|
-
name: question.name,
|
|
470
|
-
type: 'SOA',
|
|
471
|
-
class: 'IN',
|
|
472
|
-
ttl: 3600,
|
|
473
|
-
data: {
|
|
474
|
-
mname: this.options.primaryNameserver || `ns1.${this.options.dnssecZone}`,
|
|
475
|
-
rname: `hostmaster.${this.options.dnssecZone}`,
|
|
476
|
-
serial: Math.floor(Date.now() / 1000),
|
|
477
|
-
refresh: 3600,
|
|
478
|
-
retry: 600,
|
|
479
|
-
expire: 604800,
|
|
480
|
-
minimum: 86400,
|
|
481
|
-
},
|
|
482
|
-
};
|
|
483
|
-
response.answers.push(soaAnswer);
|
|
484
|
-
// Add SOA record to DNSSEC signing map if DNSSEC is requested
|
|
485
|
-
if (dnssecRequested) {
|
|
486
|
-
const soaKey = `${question.name}:SOA`;
|
|
487
|
-
rrsetMap.set(soaKey, [soaAnswer]);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
// Sign RRsets if DNSSEC is requested
|
|
492
|
-
if (dnssecRequested) {
|
|
493
|
-
for (const [key, rrset] of rrsetMap) {
|
|
494
|
-
const [name, type] = key.split(':');
|
|
495
|
-
// Sign the entire RRset together
|
|
496
|
-
const rrsig = this.generateRRSIG(type, rrset, name);
|
|
497
|
-
response.answers.push(rrsig);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
return response;
|
|
501
|
-
}
|
|
502
|
-
isDnssecRequested(request) {
|
|
503
|
-
if (!request.additionals)
|
|
504
|
-
return false;
|
|
505
|
-
for (const additional of request.additionals) {
|
|
506
|
-
if (additional.type === 'OPT' && typeof additional.flags === 'number') {
|
|
507
|
-
// The DO bit is the 15th bit (0x8000)
|
|
508
|
-
if (additional.flags & 0x8000) {
|
|
509
|
-
return true;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
return false;
|
|
514
|
-
}
|
|
515
|
-
generateRRSIG(type, rrset, name) {
|
|
516
|
-
// Prepare RRSIG data
|
|
517
|
-
const algorithm = this.dnsSec.getAlgorithmNumber();
|
|
518
|
-
const keyTag = this.keyTag;
|
|
519
|
-
const signerName = this.options.dnssecZone.endsWith('.') ? this.options.dnssecZone : `${this.options.dnssecZone}.`;
|
|
520
|
-
const inception = Math.floor(Date.now() / 1000) - 3600; // 1 hour ago
|
|
521
|
-
const expiration = inception + 86400; // Valid for 1 day
|
|
522
|
-
const ttl = rrset[0].ttl || 300;
|
|
523
|
-
// Serialize the RRset in canonical form
|
|
524
|
-
const rrsetBuffer = this.serializeRRset(rrset);
|
|
525
|
-
// Sign the RRset
|
|
526
|
-
const signature = this.dnsSec.signData(rrsetBuffer);
|
|
527
|
-
// Ensure all fields are defined
|
|
528
|
-
if (!signerName || !signature) {
|
|
529
|
-
console.error('RRSIG generation error - missing fields:', {
|
|
530
|
-
signerName,
|
|
531
|
-
signature: signature ? 'present' : 'missing',
|
|
532
|
-
algorithm,
|
|
533
|
-
keyTag,
|
|
534
|
-
type
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
// Construct the RRSIG record
|
|
538
|
-
const rrsig = {
|
|
539
|
-
name,
|
|
540
|
-
type: 'RRSIG',
|
|
541
|
-
class: 'IN',
|
|
542
|
-
ttl,
|
|
543
|
-
data: {
|
|
544
|
-
typeCovered: type, // dns-packet expects the string type
|
|
545
|
-
algorithm,
|
|
546
|
-
labels: name.split('.').filter(l => l.length > 0).length, // Fix label count
|
|
547
|
-
originalTTL: ttl,
|
|
548
|
-
expiration,
|
|
549
|
-
inception,
|
|
550
|
-
keyTag,
|
|
551
|
-
signersName: signerName || this.options.dnssecZone, // Note: signersName with 's'
|
|
552
|
-
signature: signature || Buffer.alloc(0), // Fallback to empty buffer
|
|
553
|
-
},
|
|
554
|
-
};
|
|
555
|
-
return rrsig;
|
|
556
|
-
}
|
|
557
|
-
serializeRRset(rrset) {
|
|
558
|
-
// Implement canonical DNS RRset serialization as per RFC 4034 Section 6
|
|
559
|
-
const buffers = [];
|
|
560
|
-
for (const rr of rrset) {
|
|
561
|
-
if (rr.type === 'OPT') {
|
|
562
|
-
continue; // Skip OPT records
|
|
563
|
-
}
|
|
564
|
-
const name = rr.name.endsWith('.') ? rr.name : rr.name + '.';
|
|
565
|
-
const nameBuffer = this.nameToBuffer(name.toLowerCase());
|
|
566
|
-
const typeValue = this.qtypeToNumber(rr.type);
|
|
567
|
-
const typeBuffer = Buffer.alloc(2);
|
|
568
|
-
typeBuffer.writeUInt16BE(typeValue, 0);
|
|
569
|
-
const classValue = this.classToNumber(rr.class);
|
|
570
|
-
const classBuffer = Buffer.alloc(2);
|
|
571
|
-
classBuffer.writeUInt16BE(classValue, 0);
|
|
572
|
-
const ttlValue = rr.ttl || 300;
|
|
573
|
-
const ttlBuffer = Buffer.alloc(4);
|
|
574
|
-
ttlBuffer.writeUInt32BE(ttlValue, 0);
|
|
575
|
-
// Serialize the data based on the record type
|
|
576
|
-
const dataBuffer = this.serializeRData(rr.type, rr.data);
|
|
577
|
-
const rdLengthBuffer = Buffer.alloc(2);
|
|
578
|
-
rdLengthBuffer.writeUInt16BE(dataBuffer.length, 0);
|
|
579
|
-
buffers.push(Buffer.concat([nameBuffer, typeBuffer, classBuffer, ttlBuffer, rdLengthBuffer, dataBuffer]));
|
|
580
|
-
}
|
|
581
|
-
return Buffer.concat(buffers);
|
|
582
|
-
}
|
|
583
|
-
serializeRData(type, data) {
|
|
584
|
-
// Implement serialization for each record type you support
|
|
585
|
-
switch (type) {
|
|
586
|
-
case 'A':
|
|
587
|
-
return Buffer.from(data.split('.').map((octet) => parseInt(octet, 10)));
|
|
588
|
-
case 'AAAA':
|
|
589
|
-
// Handle IPv6 addresses
|
|
590
|
-
return Buffer.from(data.split(':').flatMap((segment) => {
|
|
591
|
-
const num = parseInt(segment, 16);
|
|
592
|
-
return [num >> 8, num & 0xff];
|
|
593
|
-
}));
|
|
594
|
-
case 'TXT':
|
|
595
|
-
// Handle TXT records for ACME challenges
|
|
596
|
-
if (Array.isArray(data)) {
|
|
597
|
-
// Combine all strings and encode as lengths and values
|
|
598
|
-
const buffers = data.map(str => {
|
|
599
|
-
const strBuf = Buffer.from(str);
|
|
600
|
-
const lenBuf = Buffer.alloc(1);
|
|
601
|
-
lenBuf.writeUInt8(strBuf.length, 0);
|
|
602
|
-
return Buffer.concat([lenBuf, strBuf]);
|
|
603
|
-
});
|
|
604
|
-
return Buffer.concat(buffers);
|
|
605
|
-
}
|
|
606
|
-
return Buffer.alloc(0);
|
|
607
|
-
case 'DNSKEY':
|
|
608
|
-
const dnskeyData = data;
|
|
609
|
-
return Buffer.concat([
|
|
610
|
-
Buffer.from([dnskeyData.flags >> 8, dnskeyData.flags & 0xff]),
|
|
611
|
-
Buffer.from([3]), // Protocol field, always 3
|
|
612
|
-
Buffer.from([dnskeyData.algorithm]),
|
|
613
|
-
dnskeyData.key,
|
|
614
|
-
]);
|
|
615
|
-
case 'NS':
|
|
616
|
-
// NS records contain domain names
|
|
617
|
-
return this.nameToBuffer(data);
|
|
618
|
-
case 'SOA':
|
|
619
|
-
// Implement SOA record serialization according to RFC 1035
|
|
620
|
-
const mname = this.nameToBuffer(data.mname);
|
|
621
|
-
const rname = this.nameToBuffer(data.rname);
|
|
622
|
-
const serial = Buffer.alloc(4);
|
|
623
|
-
serial.writeUInt32BE(data.serial, 0);
|
|
624
|
-
const refresh = Buffer.alloc(4);
|
|
625
|
-
refresh.writeUInt32BE(data.refresh, 0);
|
|
626
|
-
const retry = Buffer.alloc(4);
|
|
627
|
-
retry.writeUInt32BE(data.retry, 0);
|
|
628
|
-
const expire = Buffer.alloc(4);
|
|
629
|
-
expire.writeUInt32BE(data.expire, 0);
|
|
630
|
-
const minimum = Buffer.alloc(4);
|
|
631
|
-
minimum.writeUInt32BE(data.minimum, 0);
|
|
632
|
-
return Buffer.concat([mname, rname, serial, refresh, retry, expire, minimum]);
|
|
633
|
-
case 'MX':
|
|
634
|
-
// MX records contain preference (16-bit) and exchange (domain name)
|
|
635
|
-
const preference = Buffer.alloc(2);
|
|
636
|
-
preference.writeUInt16BE(data.preference, 0);
|
|
637
|
-
const exchange = this.nameToBuffer(data.exchange);
|
|
638
|
-
return Buffer.concat([preference, exchange]);
|
|
639
|
-
// Add cases for other record types as needed
|
|
640
|
-
default:
|
|
641
|
-
throw new Error(`Serialization for record type ${type} is not implemented.`);
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
parseDNSKEYRecord(dnskeyRecord) {
|
|
645
|
-
// Parse the DNSKEY record string into dns-packet format
|
|
646
|
-
const parts = dnskeyRecord.trim().split(/\s+/);
|
|
647
|
-
const flags = parseInt(parts[3], 10);
|
|
648
|
-
const algorithm = parseInt(parts[5], 10);
|
|
649
|
-
const publicKeyBase64 = parts.slice(6).join('');
|
|
650
|
-
const key = Buffer.from(publicKeyBase64, 'base64');
|
|
651
|
-
return {
|
|
652
|
-
flags,
|
|
653
|
-
algorithm,
|
|
654
|
-
key,
|
|
655
|
-
};
|
|
656
|
-
}
|
|
657
|
-
computeKeyTag(dnskeyRecord) {
|
|
658
|
-
// Compute key tag as per RFC 4034 Appendix B
|
|
659
|
-
const flags = dnskeyRecord.flags;
|
|
660
|
-
const algorithm = dnskeyRecord.algorithm;
|
|
661
|
-
const key = dnskeyRecord.key;
|
|
662
|
-
const dnskeyRdata = Buffer.concat([
|
|
663
|
-
Buffer.from([flags >> 8, flags & 0xff]),
|
|
664
|
-
Buffer.from([3]), // Protocol field, always 3
|
|
665
|
-
Buffer.from([algorithm]),
|
|
666
|
-
key,
|
|
667
|
-
]);
|
|
668
|
-
let acc = 0;
|
|
669
|
-
for (let i = 0; i < dnskeyRdata.length; i++) {
|
|
670
|
-
acc += (i & 1) ? dnskeyRdata[i] : dnskeyRdata[i] << 8;
|
|
671
|
-
}
|
|
672
|
-
acc += (acc >> 16) & 0xffff;
|
|
673
|
-
return acc & 0xffff;
|
|
674
|
-
}
|
|
675
|
-
handleHttpsRequest(req, res) {
|
|
676
|
-
if (req.method === 'POST' && req.url === '/dns-query') {
|
|
677
|
-
let body = [];
|
|
678
|
-
req.on('data', (chunk) => {
|
|
679
|
-
body.push(chunk);
|
|
680
|
-
}).on('end', () => {
|
|
681
|
-
const msg = Buffer.concat(body);
|
|
682
|
-
const request = dnsPacket.decode(msg);
|
|
683
|
-
const response = this.processDnsRequest(request);
|
|
684
|
-
const responseData = dnsPacket.encode(response);
|
|
685
|
-
res.writeHead(200, { 'Content-Type': 'application/dns-message' });
|
|
686
|
-
res.end(responseData);
|
|
687
|
-
});
|
|
688
|
-
}
|
|
689
|
-
else {
|
|
690
|
-
res.writeHead(404);
|
|
691
|
-
res.end();
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
async start() {
|
|
695
|
-
// Initialize servers based on what's needed
|
|
696
|
-
if (!this.options.manualUdpMode) {
|
|
697
|
-
this.initializeUdpServer();
|
|
698
|
-
}
|
|
699
|
-
if (!this.options.manualHttpsMode) {
|
|
700
|
-
this.initializeHttpsServer();
|
|
701
|
-
}
|
|
702
|
-
// Handle different mode combinations
|
|
703
|
-
const udpManual = this.options.manualUdpMode || false;
|
|
704
|
-
const httpsManual = this.options.manualHttpsMode || false;
|
|
705
|
-
if (udpManual && httpsManual) {
|
|
706
|
-
console.log('DNS server started in full manual mode - ready to accept connections');
|
|
707
|
-
return;
|
|
708
|
-
}
|
|
709
|
-
else if (udpManual && !httpsManual) {
|
|
710
|
-
console.log('DNS server started with manual UDP mode and automatic HTTPS binding');
|
|
711
|
-
}
|
|
712
|
-
else if (!udpManual && httpsManual) {
|
|
713
|
-
console.log('DNS server started with automatic UDP binding and manual HTTPS mode');
|
|
714
|
-
}
|
|
715
|
-
// Validate interface addresses if provided
|
|
716
|
-
const udpInterface = this.options.udpBindInterface || '0.0.0.0';
|
|
717
|
-
const httpsInterface = this.options.httpsBindInterface || '0.0.0.0';
|
|
718
|
-
if (this.options.udpBindInterface && !this.isValidIpAddress(this.options.udpBindInterface)) {
|
|
719
|
-
throw new Error(`Invalid UDP bind interface: ${this.options.udpBindInterface}`);
|
|
720
|
-
}
|
|
721
|
-
if (this.options.httpsBindInterface && !this.isValidIpAddress(this.options.httpsBindInterface)) {
|
|
722
|
-
throw new Error(`Invalid HTTPS bind interface: ${this.options.httpsBindInterface}`);
|
|
723
|
-
}
|
|
724
|
-
const promises = [];
|
|
725
|
-
// Bind UDP if not in manual UDP mode
|
|
726
|
-
if (!udpManual) {
|
|
727
|
-
const udpListeningDeferred = plugins.smartpromise.defer();
|
|
728
|
-
promises.push(udpListeningDeferred.promise);
|
|
729
|
-
try {
|
|
730
|
-
this.udpServer.bind(this.options.udpPort, udpInterface, () => {
|
|
731
|
-
console.log(`UDP DNS server running on ${udpInterface}:${this.options.udpPort}`);
|
|
732
|
-
udpListeningDeferred.resolve();
|
|
733
|
-
});
|
|
734
|
-
}
|
|
735
|
-
catch (err) {
|
|
736
|
-
console.error('Error starting UDP DNS server:', err);
|
|
737
|
-
udpListeningDeferred.reject(err);
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
// Bind HTTPS if not in manual HTTPS mode
|
|
741
|
-
if (!httpsManual) {
|
|
742
|
-
const httpsListeningDeferred = plugins.smartpromise.defer();
|
|
743
|
-
promises.push(httpsListeningDeferred.promise);
|
|
744
|
-
try {
|
|
745
|
-
this.httpsServer.listen(this.options.httpsPort, httpsInterface, () => {
|
|
746
|
-
console.log(`HTTPS DNS server running on ${httpsInterface}:${this.options.httpsPort}`);
|
|
747
|
-
httpsListeningDeferred.resolve();
|
|
748
|
-
});
|
|
749
|
-
}
|
|
750
|
-
catch (err) {
|
|
751
|
-
console.error('Error starting HTTPS DNS server:', err);
|
|
752
|
-
httpsListeningDeferred.reject(err);
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
if (promises.length > 0) {
|
|
756
|
-
await Promise.all(promises);
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
async stop() {
|
|
760
|
-
const doneUdp = plugins.smartpromise.defer();
|
|
761
|
-
const doneHttps = plugins.smartpromise.defer();
|
|
762
|
-
if (this.udpServer) {
|
|
763
|
-
this.udpServer.close(() => {
|
|
764
|
-
console.log('UDP DNS server stopped');
|
|
765
|
-
if (this.udpServer) {
|
|
766
|
-
this.udpServer.unref();
|
|
767
|
-
this.udpServer = null;
|
|
768
|
-
}
|
|
769
|
-
doneUdp.resolve();
|
|
770
|
-
});
|
|
771
|
-
}
|
|
772
|
-
else {
|
|
773
|
-
doneUdp.resolve();
|
|
774
|
-
}
|
|
775
|
-
if (this.httpsServer) {
|
|
776
|
-
this.httpsServer.close(() => {
|
|
777
|
-
console.log('HTTPS DNS server stopped');
|
|
778
|
-
if (this.httpsServer) {
|
|
779
|
-
this.httpsServer.unref();
|
|
780
|
-
this.httpsServer = null;
|
|
781
|
-
}
|
|
782
|
-
doneHttps.resolve();
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
else {
|
|
786
|
-
doneHttps.resolve();
|
|
787
|
-
}
|
|
788
|
-
await Promise.all([doneUdp.promise, doneHttps.promise]);
|
|
789
|
-
this.udpServerInitialized = false;
|
|
790
|
-
this.httpsServerInitialized = false;
|
|
791
|
-
}
|
|
792
|
-
// Helper methods
|
|
793
|
-
qtypeToNumber(type) {
|
|
794
|
-
const QTYPE_NUMBERS = {
|
|
795
|
-
'A': 1,
|
|
796
|
-
'NS': 2,
|
|
797
|
-
'CNAME': 5,
|
|
798
|
-
'SOA': 6,
|
|
799
|
-
'PTR': 12,
|
|
800
|
-
'MX': 15,
|
|
801
|
-
'TXT': 16,
|
|
802
|
-
'AAAA': 28,
|
|
803
|
-
'SRV': 33,
|
|
804
|
-
'DNSKEY': 48,
|
|
805
|
-
'RRSIG': 46,
|
|
806
|
-
// Add more as needed
|
|
807
|
-
};
|
|
808
|
-
return QTYPE_NUMBERS[type.toUpperCase()] || 0;
|
|
809
|
-
}
|
|
810
|
-
classToNumber(cls) {
|
|
811
|
-
const CLASS_NUMBERS = {
|
|
812
|
-
'IN': 1,
|
|
813
|
-
'CH': 3,
|
|
814
|
-
'HS': 4,
|
|
815
|
-
// Add more as needed
|
|
816
|
-
};
|
|
817
|
-
if (typeof cls === 'number') {
|
|
818
|
-
return cls;
|
|
819
|
-
}
|
|
820
|
-
return CLASS_NUMBERS[cls.toUpperCase()] || 1;
|
|
821
|
-
}
|
|
822
|
-
nameToBuffer(name) {
|
|
823
|
-
const labels = name.split('.');
|
|
824
|
-
const buffers = labels.map(label => {
|
|
825
|
-
const len = Buffer.byteLength(label, 'utf8');
|
|
826
|
-
const buf = Buffer.alloc(1 + len);
|
|
827
|
-
buf.writeUInt8(len, 0);
|
|
828
|
-
buf.write(label, 1);
|
|
829
|
-
return buf;
|
|
830
|
-
});
|
|
831
|
-
return Buffer.concat([...buffers, Buffer.from([0])]); // Add root label
|
|
832
|
-
}
|
|
833
486
|
}
|
|
834
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5kbnNzZXJ2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19zZXJ2ZXIvY2xhc3Nlcy5kbnNzZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzdDLE9BQU8sS0FBSyxTQUFTLE1BQU0sWUFBWSxDQUFDO0FBNkN4QyxNQUFNLE9BQU8sU0FBUztJQWNwQixZQUFvQixPQUEwQjtRQUExQixZQUFPLEdBQVAsT0FBTyxDQUFtQjtRQVh0QyxhQUFRLEdBQWtCLEVBQUUsQ0FBQztRQU9yQyxtQ0FBbUM7UUFDM0IseUJBQW9CLEdBQVksS0FBSyxDQUFDO1FBQ3RDLDJCQUFzQixHQUFZLEtBQUssQ0FBQztRQUc5QyxvQkFBb0I7UUFDcEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQztZQUN2QixJQUFJLEVBQUUsT0FBTyxDQUFDLFVBQVU7WUFDeEIsU0FBUyxFQUFFLE9BQU8sRUFBRSwwQ0FBMEM7WUFDOUQsT0FBTyxFQUFFLEdBQUc7WUFDWixJQUFJLEVBQUUsR0FBRztTQUNWLENBQUMsQ0FBQztRQUVILGlDQUFpQztRQUNqQyxNQUFNLEVBQUUsWUFBWSxFQUFFLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUV2RCw2Q0FBNkM7UUFDN0MsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDekQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksaUJBQWlCO1FBQ3RCLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBQzNCLElBQUksQ0FBQyxxQkFBcUIsRUFB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
|
|
487
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5kbnNzZXJ2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19zZXJ2ZXIvY2xhc3Nlcy5kbnNzZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLGFBQWEsRUFBZ0UsTUFBTSw0QkFBNEIsQ0FBQztBQUN6SCxPQUFPLEtBQUssU0FBUyxNQUFNLFlBQVksQ0FBQztBQXdDeEMsTUFBTSxPQUFPLFNBQVM7SUFXcEIsWUFBb0IsT0FBMEI7UUFBMUIsWUFBTyxHQUFQLE9BQU8sQ0FBbUI7UUFUdEMsYUFBUSxHQUFrQixFQUFFLENBQUM7UUFFckMsNkJBQTZCO1FBQ3JCLGtCQUFhLEdBQVksS0FBSyxDQUFDO1FBRXZDLHNFQUFzRTtRQUM5RCxnQkFBVyxHQUFRLElBQUksQ0FBQztRQUN4QixjQUFTLEdBQVEsSUFBSSxDQUFDO1FBRzVCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxhQUFhLEVBQUUsQ0FBQztRQUVsQyx3REFBd0Q7UUFDeEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxFQUFFLEtBQUssRUFBRSxLQUFxQixFQUFFLEVBQUU7WUFDekQsSUFBSSxDQUFDO2dCQUNILE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ3pDLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLENBQy9CLEtBQUssQ0FBQyxhQUFhLEVBQ25CLE9BQU8sQ0FBQyxPQUFPLEVBQ2YsT0FBTyxDQUFDLFFBQVEsQ0FDakIsQ0FBQztZQUNKLENBQUM7WUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO2dCQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsMkJBQTJCLEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBQ2hELElBQUksQ0FBQztvQkFDSCxNQUFNLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxD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
|