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