Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
459b3894b5 | |||
f7b357e80b |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@push.rocks/smartdns",
|
"name": "@push.rocks/smartdns",
|
||||||
"version": "7.4.6",
|
"version": "7.4.4",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A robust TypeScript library providing advanced DNS management and resolution capabilities including support for DNSSEC, custom DNS servers, and integration with various DNS providers.",
|
"description": "A robust TypeScript library providing advanced DNS management and resolution capabilities including support for DNSSEC, custom DNS servers, and integration with various DNS providers.",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
@ -1,269 +0,0 @@
|
|||||||
import * as plugins from '../ts_server/plugins.js';
|
|
||||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
||||||
import { tapNodeTools } from '@git.zone/tstest/tapbundle_node';
|
|
||||||
import * as dnsPacket from 'dns-packet';
|
|
||||||
import * as dgram from 'dgram';
|
|
||||||
|
|
||||||
import * as smartdns from '../ts_server/index.js';
|
|
||||||
|
|
||||||
let dnsServer: smartdns.DnsServer;
|
|
||||||
|
|
||||||
// Port management for tests
|
|
||||||
let nextHttpsPort = 8700;
|
|
||||||
let nextUdpPort = 8701;
|
|
||||||
|
|
||||||
function getUniqueHttpsPort() {
|
|
||||||
return nextHttpsPort++;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUniqueUdpPort() {
|
|
||||||
return nextUdpPort++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup function for servers
|
|
||||||
async function stopServer(server: smartdns.DnsServer | null | undefined) {
|
|
||||||
if (!server) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await server.stop();
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Handled error when stopping server:', e.message || e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tap.test('Direct SOA query should work without timeout', async () => {
|
|
||||||
const httpsData = await tapNodeTools.createHttpsCert();
|
|
||||||
const udpPort = getUniqueUdpPort();
|
|
||||||
|
|
||||||
dnsServer = new smartdns.DnsServer({
|
|
||||||
httpsKey: httpsData.key,
|
|
||||||
httpsCert: httpsData.cert,
|
|
||||||
httpsPort: getUniqueHttpsPort(),
|
|
||||||
udpPort: udpPort,
|
|
||||||
dnssecZone: 'example.com',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Register a SOA handler directly
|
|
||||||
dnsServer.registerHandler('example.com', ['SOA'], (question) => {
|
|
||||||
console.log('Direct SOA handler called for:', question.name);
|
|
||||||
return {
|
|
||||||
name: question.name,
|
|
||||||
type: 'SOA',
|
|
||||||
class: 'IN',
|
|
||||||
ttl: 3600,
|
|
||||||
data: {
|
|
||||||
mname: 'ns1.example.com',
|
|
||||||
rname: 'hostmaster.example.com',
|
|
||||||
serial: 2024010101,
|
|
||||||
refresh: 3600,
|
|
||||||
retry: 600,
|
|
||||||
expire: 604800,
|
|
||||||
minimum: 86400,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
await dnsServer.start();
|
|
||||||
|
|
||||||
const client = dgram.createSocket('udp4');
|
|
||||||
|
|
||||||
const query = dnsPacket.encode({
|
|
||||||
type: 'query',
|
|
||||||
id: 1,
|
|
||||||
flags: dnsPacket.RECURSION_DESIRED,
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
name: 'example.com',
|
|
||||||
type: 'SOA',
|
|
||||||
class: 'IN',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Sending SOA query for example.com');
|
|
||||||
|
|
||||||
const responsePromise = new Promise<dnsPacket.Packet>((resolve, reject) => {
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
client.close();
|
|
||||||
reject(new Error('Query timed out after 5 seconds'));
|
|
||||||
}, 5000);
|
|
||||||
|
|
||||||
client.on('message', (msg) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
try {
|
|
||||||
const dnsResponse = dnsPacket.decode(msg);
|
|
||||||
resolve(dnsResponse);
|
|
||||||
} catch (e) {
|
|
||||||
reject(new Error(`Failed to decode response: ${e.message}`));
|
|
||||||
}
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('error', (err) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(err);
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.send(query, udpPort, 'localhost', (err) => {
|
|
||||||
if (err) {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(err);
|
|
||||||
client.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const dnsResponse = await responsePromise;
|
|
||||||
console.log('SOA response received:', dnsResponse.answers.length, 'answers');
|
|
||||||
|
|
||||||
const soaAnswers = dnsResponse.answers.filter(a => a.type === 'SOA');
|
|
||||||
expect(soaAnswers.length).toEqual(1);
|
|
||||||
|
|
||||||
const soaData = (soaAnswers[0] as any).data;
|
|
||||||
console.log('SOA data:', soaData);
|
|
||||||
|
|
||||||
expect(soaData.mname).toEqual('ns1.example.com');
|
|
||||||
expect(soaData.serial).toEqual(2024010101);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('SOA query failed:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
await stopServer(dnsServer);
|
|
||||||
dnsServer = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
tap.test('SOA query with DNSSEC should work', async () => {
|
|
||||||
const httpsData = await tapNodeTools.createHttpsCert();
|
|
||||||
const udpPort = getUniqueUdpPort();
|
|
||||||
|
|
||||||
dnsServer = new smartdns.DnsServer({
|
|
||||||
httpsKey: httpsData.key,
|
|
||||||
httpsCert: httpsData.cert,
|
|
||||||
httpsPort: getUniqueHttpsPort(),
|
|
||||||
udpPort: udpPort,
|
|
||||||
dnssecZone: 'example.com',
|
|
||||||
});
|
|
||||||
|
|
||||||
await dnsServer.start();
|
|
||||||
|
|
||||||
const client = dgram.createSocket('udp4');
|
|
||||||
|
|
||||||
const query = dnsPacket.encode({
|
|
||||||
type: 'query',
|
|
||||||
id: 2,
|
|
||||||
flags: dnsPacket.RECURSION_DESIRED,
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
name: 'nonexistent.example.com',
|
|
||||||
type: 'A',
|
|
||||||
class: 'IN',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
additionals: [
|
|
||||||
{
|
|
||||||
name: '.',
|
|
||||||
type: 'OPT',
|
|
||||||
ttl: 0,
|
|
||||||
flags: 0x8000, // DO bit set for DNSSEC
|
|
||||||
data: Buffer.alloc(0),
|
|
||||||
} as any,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('Sending query for nonexistent domain with DNSSEC');
|
|
||||||
|
|
||||||
const responsePromise = new Promise<dnsPacket.Packet>((resolve, reject) => {
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
client.close();
|
|
||||||
reject(new Error('Query timed out after 5 seconds'));
|
|
||||||
}, 5000);
|
|
||||||
|
|
||||||
client.on('message', (msg) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
try {
|
|
||||||
const dnsResponse = dnsPacket.decode(msg);
|
|
||||||
resolve(dnsResponse);
|
|
||||||
} catch (e) {
|
|
||||||
reject(new Error(`Failed to decode response: ${e.message}`));
|
|
||||||
}
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('error', (err) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(err);
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.send(query, udpPort, 'localhost', (err) => {
|
|
||||||
if (err) {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(err);
|
|
||||||
client.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const dnsResponse = await responsePromise;
|
|
||||||
console.log('Response received with', dnsResponse.answers.length, 'answers');
|
|
||||||
|
|
||||||
const soaAnswers = dnsResponse.answers.filter(a => a.type === 'SOA');
|
|
||||||
console.log('SOA records found:', soaAnswers.length);
|
|
||||||
|
|
||||||
if (soaAnswers.length > 0) {
|
|
||||||
const soaData = (soaAnswers[0] as any).data;
|
|
||||||
console.log('SOA data:', soaData);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('SOA query with DNSSEC failed:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
await stopServer(dnsServer);
|
|
||||||
dnsServer = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
tap.test('Test raw SOA serialization', async () => {
|
|
||||||
const httpsData = await tapNodeTools.createHttpsCert();
|
|
||||||
|
|
||||||
dnsServer = new smartdns.DnsServer({
|
|
||||||
httpsKey: httpsData.key,
|
|
||||||
httpsCert: httpsData.cert,
|
|
||||||
httpsPort: getUniqueHttpsPort(),
|
|
||||||
udpPort: getUniqueUdpPort(),
|
|
||||||
dnssecZone: 'example.com',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Test the serializeRData method directly
|
|
||||||
const soaData = {
|
|
||||||
mname: 'ns1.example.com',
|
|
||||||
rname: 'hostmaster.example.com',
|
|
||||||
serial: 2024010101,
|
|
||||||
refresh: 3600,
|
|
||||||
retry: 600,
|
|
||||||
expire: 604800,
|
|
||||||
minimum: 86400,
|
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
|
||||||
// @ts-ignore - accessing private method for testing
|
|
||||||
const serialized = dnsServer.serializeRData('SOA', soaData);
|
|
||||||
console.log('SOA serialized successfully, buffer length:', serialized.length);
|
|
||||||
expect(serialized.length).toBeGreaterThan(0);
|
|
||||||
|
|
||||||
// The buffer should contain the serialized domain names + 5 * 4 bytes for the numbers
|
|
||||||
// Domain names have variable length, but should be at least 20 bytes total
|
|
||||||
expect(serialized.length).toBeGreaterThan(20);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('SOA serialization failed:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default tap.start();
|
|
@ -1,201 +0,0 @@
|
|||||||
import * as plugins from '../ts_server/plugins.js';
|
|
||||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
||||||
import { tapNodeTools } from '@git.zone/tstest/tapbundle_node';
|
|
||||||
import * as dnsPacket from 'dns-packet';
|
|
||||||
import * as dgram from 'dgram';
|
|
||||||
|
|
||||||
import * as smartdns from '../ts_server/index.js';
|
|
||||||
|
|
||||||
let dnsServer: smartdns.DnsServer;
|
|
||||||
|
|
||||||
// Port management for tests
|
|
||||||
let nextHttpsPort = 8800;
|
|
||||||
let nextUdpPort = 8801;
|
|
||||||
|
|
||||||
function getUniqueHttpsPort() {
|
|
||||||
return nextHttpsPort++;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getUniqueUdpPort() {
|
|
||||||
return nextUdpPort++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup function for servers
|
|
||||||
async function stopServer(server: smartdns.DnsServer | null | undefined) {
|
|
||||||
if (!server) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await server.stop();
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Handled error when stopping server:', e.message || e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tap.test('Simple SOA query without DNSSEC', async () => {
|
|
||||||
const httpsData = await tapNodeTools.createHttpsCert();
|
|
||||||
const udpPort = getUniqueUdpPort();
|
|
||||||
|
|
||||||
dnsServer = new smartdns.DnsServer({
|
|
||||||
httpsKey: httpsData.key,
|
|
||||||
httpsCert: httpsData.cert,
|
|
||||||
httpsPort: getUniqueHttpsPort(),
|
|
||||||
udpPort: udpPort,
|
|
||||||
dnssecZone: 'example.com',
|
|
||||||
});
|
|
||||||
|
|
||||||
await dnsServer.start();
|
|
||||||
|
|
||||||
const client = dgram.createSocket('udp4');
|
|
||||||
|
|
||||||
// Query for a non-existent domain WITHOUT DNSSEC
|
|
||||||
const query = dnsPacket.encode({
|
|
||||||
type: 'query',
|
|
||||||
id: 1,
|
|
||||||
flags: dnsPacket.RECURSION_DESIRED,
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
name: 'nonexistent.example.com',
|
|
||||||
type: 'A',
|
|
||||||
class: 'IN',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const responsePromise = new Promise<dnsPacket.Packet>((resolve, reject) => {
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
client.close();
|
|
||||||
reject(new Error('Query timed out'));
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
client.on('message', (msg) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
try {
|
|
||||||
const dnsResponse = dnsPacket.decode(msg);
|
|
||||||
resolve(dnsResponse);
|
|
||||||
} catch (e) {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('error', (err) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(err);
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.send(query, udpPort, 'localhost', (err) => {
|
|
||||||
if (err) {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(err);
|
|
||||||
client.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const dnsResponse = await responsePromise;
|
|
||||||
console.log('✅ SOA response without DNSSEC received');
|
|
||||||
|
|
||||||
const soaAnswers = dnsResponse.answers.filter(a => a.type === 'SOA');
|
|
||||||
expect(soaAnswers.length).toEqual(1);
|
|
||||||
|
|
||||||
const soaData = (soaAnswers[0] as any).data;
|
|
||||||
console.log('✅ SOA data:', soaData.mname);
|
|
||||||
|
|
||||||
await stopServer(dnsServer);
|
|
||||||
dnsServer = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
tap.test('Direct SOA query without DNSSEC', async () => {
|
|
||||||
const httpsData = await tapNodeTools.createHttpsCert();
|
|
||||||
const udpPort = getUniqueUdpPort();
|
|
||||||
|
|
||||||
dnsServer = new smartdns.DnsServer({
|
|
||||||
httpsKey: httpsData.key,
|
|
||||||
httpsCert: httpsData.cert,
|
|
||||||
httpsPort: getUniqueHttpsPort(),
|
|
||||||
udpPort: udpPort,
|
|
||||||
dnssecZone: 'example.com',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Register direct SOA handler
|
|
||||||
dnsServer.registerHandler('example.com', ['SOA'], (question) => {
|
|
||||||
return {
|
|
||||||
name: question.name,
|
|
||||||
type: 'SOA',
|
|
||||||
class: 'IN',
|
|
||||||
ttl: 3600,
|
|
||||||
data: {
|
|
||||||
mname: 'ns1.example.com',
|
|
||||||
rname: 'hostmaster.example.com',
|
|
||||||
serial: 2024010101,
|
|
||||||
refresh: 3600,
|
|
||||||
retry: 600,
|
|
||||||
expire: 604800,
|
|
||||||
minimum: 86400,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
await dnsServer.start();
|
|
||||||
|
|
||||||
const client = dgram.createSocket('udp4');
|
|
||||||
|
|
||||||
const query = dnsPacket.encode({
|
|
||||||
type: 'query',
|
|
||||||
id: 2,
|
|
||||||
flags: dnsPacket.RECURSION_DESIRED,
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
name: 'example.com',
|
|
||||||
type: 'SOA',
|
|
||||||
class: 'IN',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const responsePromise = new Promise<dnsPacket.Packet>((resolve, reject) => {
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
client.close();
|
|
||||||
reject(new Error('Query timed out'));
|
|
||||||
}, 2000);
|
|
||||||
|
|
||||||
client.on('message', (msg) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
try {
|
|
||||||
const dnsResponse = dnsPacket.decode(msg);
|
|
||||||
resolve(dnsResponse);
|
|
||||||
} catch (e) {
|
|
||||||
reject(e);
|
|
||||||
}
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('error', (err) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(err);
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.send(query, udpPort, 'localhost', (err) => {
|
|
||||||
if (err) {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(err);
|
|
||||||
client.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const dnsResponse = await responsePromise;
|
|
||||||
console.log('✅ Direct SOA query succeeded');
|
|
||||||
|
|
||||||
const soaAnswers = dnsResponse.answers.filter(a => a.type === 'SOA');
|
|
||||||
expect(soaAnswers.length).toEqual(1);
|
|
||||||
|
|
||||||
await stopServer(dnsServer);
|
|
||||||
dnsServer = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
export default tap.start();
|
|
@ -1,224 +0,0 @@
|
|||||||
import * as plugins from '../ts_server/plugins.js';
|
|
||||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
||||||
import { tapNodeTools } from '@git.zone/tstest/tapbundle_node';
|
|
||||||
import * as dnsPacket from 'dns-packet';
|
|
||||||
import * as dgram from 'dgram';
|
|
||||||
import { execSync } from 'child_process';
|
|
||||||
|
|
||||||
import * as smartdns from '../ts_server/index.js';
|
|
||||||
|
|
||||||
let dnsServer: smartdns.DnsServer;
|
|
||||||
|
|
||||||
// Port management for tests
|
|
||||||
const testPort = 8753;
|
|
||||||
|
|
||||||
// Cleanup function for servers
|
|
||||||
async function stopServer(server: smartdns.DnsServer | null | undefined) {
|
|
||||||
if (!server) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await server.stop();
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Handled error when stopping server:', e.message || e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tap.test('Test SOA timeout with real dig command', async (tools) => {
|
|
||||||
const httpsData = await tapNodeTools.createHttpsCert();
|
|
||||||
|
|
||||||
dnsServer = new smartdns.DnsServer({
|
|
||||||
httpsKey: httpsData.key,
|
|
||||||
httpsCert: httpsData.cert,
|
|
||||||
httpsPort: 8752,
|
|
||||||
udpPort: testPort,
|
|
||||||
dnssecZone: 'example.com',
|
|
||||||
});
|
|
||||||
|
|
||||||
await dnsServer.start();
|
|
||||||
console.log(`DNS server started on port ${testPort}`);
|
|
||||||
|
|
||||||
// Test with dig command
|
|
||||||
try {
|
|
||||||
console.log('Testing SOA query with dig...');
|
|
||||||
const result = execSync(`dig @localhost -p ${testPort} example.com SOA +timeout=3`, { encoding: 'utf8' });
|
|
||||||
console.log('Dig SOA query result:', result);
|
|
||||||
|
|
||||||
// Check if we got an answer section
|
|
||||||
expect(result).toInclude('ANSWER SECTION');
|
|
||||||
expect(result).toInclude('SOA');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Dig command failed:', error.message);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test nonexistent domain SOA
|
|
||||||
try {
|
|
||||||
console.log('Testing nonexistent domain SOA query with dig...');
|
|
||||||
const result = execSync(`dig @localhost -p ${testPort} nonexistent.example.com A +timeout=3`, { encoding: 'utf8' });
|
|
||||||
console.log('Dig nonexistent query result:', result);
|
|
||||||
|
|
||||||
// Should get AUTHORITY section with SOA
|
|
||||||
expect(result).toInclude('AUTHORITY SECTION');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Dig nonexistent query failed:', error.message);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
await stopServer(dnsServer);
|
|
||||||
dnsServer = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
tap.test('Test SOA with DNSSEC timing', async () => {
|
|
||||||
const httpsData = await tapNodeTools.createHttpsCert();
|
|
||||||
const udpPort = 8754;
|
|
||||||
|
|
||||||
dnsServer = new smartdns.DnsServer({
|
|
||||||
httpsKey: httpsData.key,
|
|
||||||
httpsCert: httpsData.cert,
|
|
||||||
httpsPort: 8755,
|
|
||||||
udpPort: udpPort,
|
|
||||||
dnssecZone: 'example.com',
|
|
||||||
});
|
|
||||||
|
|
||||||
await dnsServer.start();
|
|
||||||
|
|
||||||
const client = dgram.createSocket('udp4');
|
|
||||||
|
|
||||||
// Test with DNSSEC enabled
|
|
||||||
const query = dnsPacket.encode({
|
|
||||||
type: 'query',
|
|
||||||
id: 1,
|
|
||||||
flags: dnsPacket.RECURSION_DESIRED,
|
|
||||||
questions: [
|
|
||||||
{
|
|
||||||
name: 'nonexistent.example.com',
|
|
||||||
type: 'A',
|
|
||||||
class: 'IN',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
additionals: [
|
|
||||||
{
|
|
||||||
name: '.',
|
|
||||||
type: 'OPT',
|
|
||||||
ttl: 0,
|
|
||||||
flags: 0x8000, // DO bit set for DNSSEC
|
|
||||||
data: Buffer.alloc(0),
|
|
||||||
} as any,
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
const startTime = Date.now();
|
|
||||||
console.log('Sending DNSSEC query for nonexistent domain...');
|
|
||||||
|
|
||||||
const responsePromise = new Promise<dnsPacket.Packet>((resolve, reject) => {
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
client.close();
|
|
||||||
const elapsed = Date.now() - startTime;
|
|
||||||
reject(new Error(`Query timed out after ${elapsed}ms`));
|
|
||||||
}, 3000);
|
|
||||||
|
|
||||||
client.on('message', (msg) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
const elapsed = Date.now() - startTime;
|
|
||||||
console.log(`Response received in ${elapsed}ms`);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const dnsResponse = dnsPacket.decode(msg);
|
|
||||||
resolve(dnsResponse);
|
|
||||||
} catch (e) {
|
|
||||||
reject(new Error(`Failed to decode response: ${e.message}`));
|
|
||||||
}
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.on('error', (err) => {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
const elapsed = Date.now() - startTime;
|
|
||||||
console.error(`Error after ${elapsed}ms:`, err);
|
|
||||||
reject(err);
|
|
||||||
client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
client.send(query, udpPort, 'localhost', (err) => {
|
|
||||||
if (err) {
|
|
||||||
clearTimeout(timeout);
|
|
||||||
reject(err);
|
|
||||||
client.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const dnsResponse = await responsePromise;
|
|
||||||
console.log('Response details:');
|
|
||||||
console.log('- Answers:', dnsResponse.answers.length);
|
|
||||||
console.log('- Answer types:', dnsResponse.answers.map(a => a.type));
|
|
||||||
|
|
||||||
const soaAnswers = dnsResponse.answers.filter(a => a.type === 'SOA');
|
|
||||||
const rrsigAnswers = dnsResponse.answers.filter(a => a.type === 'RRSIG');
|
|
||||||
|
|
||||||
console.log('- SOA records:', soaAnswers.length);
|
|
||||||
console.log('- RRSIG records:', rrsigAnswers.length);
|
|
||||||
|
|
||||||
// With the fix, SOA should have its RRSIG
|
|
||||||
if (soaAnswers.length > 0) {
|
|
||||||
expect(rrsigAnswers.length).toBeGreaterThan(0);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('DNSSEC SOA query failed:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
await stopServer(dnsServer);
|
|
||||||
dnsServer = null;
|
|
||||||
});
|
|
||||||
|
|
||||||
tap.test('Check DNSSEC signing performance for SOA', async () => {
|
|
||||||
const httpsData = await tapNodeTools.createHttpsCert();
|
|
||||||
|
|
||||||
dnsServer = new smartdns.DnsServer({
|
|
||||||
httpsKey: httpsData.key,
|
|
||||||
httpsCert: httpsData.cert,
|
|
||||||
httpsPort: 8756,
|
|
||||||
udpPort: 8757,
|
|
||||||
dnssecZone: 'example.com',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Time SOA serialization
|
|
||||||
const soaData = {
|
|
||||||
mname: 'ns1.example.com',
|
|
||||||
rname: 'hostmaster.example.com',
|
|
||||||
serial: 2024010101,
|
|
||||||
refresh: 3600,
|
|
||||||
retry: 600,
|
|
||||||
expire: 604800,
|
|
||||||
minimum: 86400,
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('Testing SOA serialization performance...');
|
|
||||||
const serializeStart = Date.now();
|
|
||||||
|
|
||||||
try {
|
|
||||||
// @ts-ignore - accessing private method for testing
|
|
||||||
const serialized = dnsServer.serializeRData('SOA', soaData);
|
|
||||||
const serializeTime = Date.now() - serializeStart;
|
|
||||||
console.log(`SOA serialization took ${serializeTime}ms`);
|
|
||||||
|
|
||||||
// Test DNSSEC signing
|
|
||||||
const signStart = Date.now();
|
|
||||||
// @ts-ignore - accessing private property
|
|
||||||
const signature = dnsServer.dnsSec.signData(serialized);
|
|
||||||
const signTime = Date.now() - signStart;
|
|
||||||
console.log(`DNSSEC signing took ${signTime}ms`);
|
|
||||||
|
|
||||||
expect(serializeTime).toBeLessThan(100); // Should be fast
|
|
||||||
expect(signTime).toBeLessThan(500); // Signing can take longer but shouldn't timeout
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Performance test failed:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default tap.start();
|
|
Reference in New Issue
Block a user