Skip to content

Instantly share code, notes, and snippets.

@greenido
Created February 5, 2025 02:34
Show Gist options
  • Save greenido/90994e70458b3cc0b8a5fe745a6dfc82 to your computer and use it in GitHub Desktop.
Save greenido/90994e70458b3cc0b8a5fe745a6dfc82 to your computer and use it in GitHub Desktop.
Checking the DNS or CloudFlare (both 9.9.9.9 and 1.1.1.3)
// Save this file as dns-check.mjs
import fetch from 'node-fetch';
import { performance } from 'perf_hooks';
// Configure DoH endpoints
const quad9 = {
name: 'Quad9',
endpoint: 'https://dns.quad9.net:5053/dns-query'
};
const cloudflareSecure = {
name: 'Cloudflare Security',
endpoint: 'https://security.cloudflare-dns.com/dns-query'
};
// Test URLs
const safeUrls = [
'google.com',
'microsoft.com',
'amazon.com',
'github.com',
'netflix.com'
];
const suspiciousUrls = [
'githb.co', // REAL ungly domain
'malware.testcategory.quad9.net',
'eicartest.quad9.net', // Quad9 test domain
'eicar.ph', // Known malware test domain
'blocked.quad9.net', // Quad9 test domain
'fraud.sb' // Known fraud domain
];
async function dnsQuery(domain, dnsServer) {
const startTime = performance.now();
try {
// Make DoH request
const response = await fetch(`${dnsServer.endpoint}?name=${domain}&type=A`, {
headers: {
'accept': 'application/dns-json',
'Content-Type': 'application/dns-json'
}
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
const endTime = performance.now();
const responseTime = (endTime - startTime).toFixed(2);
// More detailed status checking
let status = 'ALLOWED';
let addresses = [];
let rcode = data.Status || 0;
switch (rcode) {
case 0: // NOERROR
if (data.Answer) {
addresses = data.Answer
.filter(record => record.type === 1) // Type A records
.map(record => record.data);
status = addresses.length > 0 ? 'ALLOWED' : 'NO RECORDS';
} else {
status = 'NO RECORDS';
}
break;
case 2: // SERVFAIL
status = 'BLOCKED (SERVFAIL)';
break;
case 3: // NXDOMAIN
status = 'BLOCKED (NXDOMAIN)';
break;
case 5: // REFUSED
status = 'BLOCKED (REFUSED)';
break;
default:
status = `UNKNOWN (${rcode})`;
}
return {
domain,
dnsServer: dnsServer.name,
status,
responseTime: `${responseTime}ms`,
addresses,
rcode
};
} catch (error) {
const endTime = performance.now();
const responseTime = (endTime - startTime).toFixed(2);
return {
domain,
dnsServer: dnsServer.name,
status: `ERROR: ${error.message}`,
responseTime: `${responseTime}ms`,
addresses: [],
rcode: null
};
}
}
async function runTests() {
console.log('Starting DNS-over-HTTPS Security Tests\n');
// Test all URLs against both DNS servers
const allUrls = [...safeUrls, ...suspiciousUrls];
const allTests = [];
for (const domain of allUrls) {
allTests.push(dnsQuery(domain, quad9));
allTests.push(dnsQuery(domain, cloudflareSecure));
}
try {
const results = await Promise.all(allTests);
// Process and display results with improved formatting
console.log('=== Safe URLs ===');
for (const domain of safeUrls) {
const quad9Result = results.find(r => r.domain === domain && r.dnsServer === quad9.name);
const cloudflareResult = results.find(r => r.domain === domain && r.dnsServer === cloudflareSecure.name);
console.log(`\nDomain: ${domain}`);
console.log(`${quad9.name.padEnd(20)}: ${quad9Result.status.padEnd(20)} (${quad9Result.responseTime})`);
if (quad9Result.addresses.length > 0) {
console.log(`${''.padEnd(22)}IP: ${quad9Result.addresses.join(', ')}`);
}
console.log(`${cloudflareSecure.name.padEnd(20)}: ${cloudflareResult.status.padEnd(20)} (${cloudflareResult.responseTime})`);
if (cloudflareResult.addresses.length > 0) {
console.log(`${''.padEnd(22)}IP: ${cloudflareResult.addresses.join(', ')}`);
}
}
console.log('\n=== Suspicious URLs ===');
for (const domain of suspiciousUrls) {
const quad9Result = results.find(r => r.domain === domain && r.dnsServer === quad9.name);
const cloudflareResult = results.find(r => r.domain === domain && r.dnsServer === cloudflareSecure.name);
console.log(`\nDomain: ${domain}`);
console.log(`${quad9.name.padEnd(20)}: ${quad9Result.status.padEnd(20)} (${quad9Result.responseTime})`);
if (quad9Result.addresses.length > 0) {
console.log(`${''.padEnd(22)}IP: ${quad9Result.addresses.join(', ')}`);
}
console.log(`${cloudflareSecure.name.padEnd(20)}: ${cloudflareResult.status.padEnd(20)} (${cloudflareResult.responseTime})`);
if (cloudflareResult.addresses.length > 0) {
console.log(`${''.padEnd(22)}IP: ${cloudflareResult.addresses.join(', ')}`);
}
}
// Calculate and display statistics
const quad9Times = results
.filter(r => r.dnsServer === quad9.name)
.map(r => parseFloat(r.responseTime));
const cloudflareTimes = results
.filter(r => r.dnsServer === cloudflareSecure.name)
.map(r => parseFloat(r.responseTime));
const avgQuad9Time = (quad9Times.reduce((a, b) => a + b, 0) / quad9Times.length).toFixed(2);
const avgCloudflareTime = (cloudflareTimes.reduce((a, b) => a + b, 0) / cloudflareTimes.length).toFixed(2);
console.log('\n=== Performance Summary ===');
console.log(`${quad9.name} average response time: ${avgQuad9Time}ms`);
console.log(`${cloudflareSecure.name} average response time: ${avgCloudflareTime}ms`);
} catch (error) {
console.error('Error running tests:', error);
}
}
// Run the tests
runTests().catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment