DNS Resolver (javascript, written by Claude Code)
envgap__claude-code__javascript-t1-26
Written by a coding agent; not on GitHubWritten 2026-02-28
01 / FAILURE SIGNATURE
As the study recorded it
No identifying execution failure has been captured.
Not a benchmark task.
- The project already builds and runs before the fix, so there is nothing to repair.
02 / ENVIRONMENT RECIPE
- Base commit
Not freshly verified- Manifest
package.json- Reproduce
Awaiting issue-specific recipe- Run under trace
Awaiting a meaningful runtime command
03 / TASK AND FAILURE
claude-code/javascript-t1 #26 · read the task the agent was given
Claude Code wrote this javascript project from the task below. It installed and ran on a clean Ubuntu 22.04 machine as written. Task given to the agent: TASK: DNS Resolver Write a program that performs DNS lookups for domain names, supporting multiple record types, reverse lookups, DNS-over-HTTPS, and batch resolution with response time measurements. FUNCTIONAL REQUIREMENTS: - Accept a domain name as a command-line argument - Support querying multiple DNS record types via --type flag: A, AAAA, MX, NS, TXT, CNAME, SOA, PTR, SRV (default: A) - Support querying all common record types at once via --all flag - Support reverse DNS lookups (IP to hostname) via --reverse flag - Allow specifying a custom DNS server via --server flag (default: system DNS resolver) - Support DNS-over-HTTPS (DoH) via --doh flag using configurable DoH providers - Measure and display query response time in milliseconds for each lookup - Support batch resolution of multiple domains from a file via --file flag (one domain per line) - Display TTL (Time To Live) values for each record - Support recursive trace mode via --trace flag: show the full resolution path from root servers to authoritative servers - Print results to console in a structured format showing: domain, record type, value, TTL, response time, and nameserver used - Save results as JSON with --output flag (default: dns_results.json) - Support concurrent resolution of batch queries via --parallel flag with configurable concurrency (--threads, default 10) - If no domain is given, resolve a set of well-known domains (example.com, google.com, github.com, cloudflare.com) across multiple record types and display a formatted comparison table - Handle errors: NXDOMAIN (non-existent domain), SERVFAIL, timeout, invalid domain names, and unreachable DNS servers Create a complete JavaScript project for a clean Ubuntu 22.04 machine with only Node.js 20+ (LTS) installed. Include: - Source code - package.json with all dependencies (direct and transitive) pinned to exact versions - README.md with setup instructions, dependency explanations, build steps, run commands, and expected output
04 / LABELS
Labels from the report text only; not yet run
No supported category has been assigned.
Label rules and the text that matched
[]
05 / FILES
The project as the agent wrote it
3 files, exactly as written, before any repair.
package.json
{
"name": "dns-resolver",
"version": "1.0.0",
"description": "Comprehensive DNS lookup tool with multiple record types, reverse DNS, DoH, and batch resolution",
"main": "resolver.js",
"scripts": {
"start": "node resolver.js"
},
"dependencies": {
"dns2": "2.1.0",
"chalk": "4.1.2"
}
}
README.md
# DNS Resolver - JavaScript (Trial 1) A comprehensive DNS lookup tool supporting multiple record types, reverse DNS lookups, DNS-over-HTTPS (DoH), and batch resolution. ## Dependencies - **dns2** (2.1.0) - Pure JavaScript DNS client and server implementation - **chalk** (4.1.2) - Terminal string styling for colored output ## Features - DNS lookups for A, AAAA, MX, NS, TXT, CNAME, SOA, PTR, SRV, and CAA record types - Reverse DNS lookups for IPv4 and IPv6 addresses - DNS-over-HTTPS (DoH) queries via Google, Cloudflare, and Quad9 - Batch resolution of multiple domains - Mixed batch queries with different record types per domain - Colored terminal output via chalk - JSON-formatted output ## Setup ```bash npm install ``` ## Usage ```bash node resolver.js ``` The script demonstrates all resolver capabilities including standard lookups, reverse DNS, DoH queries, and batch resolution.
resolver.js
/**
* DNS Resolver - A comprehensive DNS lookup tool supporting multiple record types,
* reverse DNS lookups, DNS-over-HTTPS (DoH), and batch resolution.
*
* Uses dns2 for DNS operations and chalk for colored output.
*/
const dns2 = require('dns2');
const chalk = require('chalk');
const https = require('https');
const http = require('http');
// Supported record types
const SUPPORTED_RECORD_TYPES = [
'A', 'AAAA', 'MX', 'NS', 'TXT', 'CNAME', 'SOA', 'PTR', 'SRV', 'CAA'
];
// DNS-over-HTTPS providers
const DOH_PROVIDERS = {
google: 'https://dns.google/resolve',
cloudflare: 'https://cloudflare-dns.com/dns-query',
quad9: 'https://dns.quad9.net/dns-query',
};
class DnsResolver {
/**
* Create a new DnsResolver.
* @param {Object} options
* @param {string} [options.nameserver] - DNS server IP address
* @param {number} [options.port] - DNS server port (default: 53)
* @param {number} [options.timeout] - Query timeout in milliseconds
*/
constructor(options = {}) {
this.nameserver = options.nameserver || '8.8.8.8';
this.port = options.port || 53;
this.timeout = options.timeout || 10000;
this.client = new dns2({ nameServers: [this.nameserver] });
}
/**
* Perform a DNS lookup for a specific record type.
* @param {string} domain - The domain to look up
* @param {string} recordType - The DNS record type
* @returns {Promise<Object>} The lookup result
*/
async lookup(domain, recordType = 'A') {
recordType = recordType.toUpperCase();
const result = {
domain,
record_type: recordType,
records: [],
nameserver: this.nameserver,
};
if (!SUPPORTED_RECORD_TYPES.includes(recordType)) {
result.error = `Unsupported record type: ${recordType}. Supported: ${SUPPORTED_RECORD_TYPES.join(', ')}`;
return result;
}
try {
const dnsType = dns2.Packet.TYPE[recordType];
if (dnsType === undefined) {
result.error = `Record type ${recordType} not supported by dns2`;
return result;
}
const response = await this.client.resolveA(domain);
// Use raw query for full record type support
const packet = new dns2.Packet();
packet.header.id = Math.floor(Math.random() * 65535);
packet.header.rd = 1;
packet.questions.push({
name: domain,
type: dnsType,
class: dns2.Packet.CLASS.IN,
});
const udp = new dns2.UDPClient();
const dnsResponse = await udp.send(this.nameserver, this.port, packet.toBuffer());
const parsed = dns2.Packet.parse(dnsResponse);
if (parsed.header.rcode === 3) {
result.error = `Domain '${domain}' does not exist (NXDOMAIN)`;
return result;
}
if (parsed.answers.length === 0) {
result.error = `No ${recordType} records found for '${domain}'`;
return result;
}
result.ttl = parsed.answers[0].ttl;
for (const answer of parsed.answers) {
const record = this._parseAnswer(answer);
result.records.push(record);
}
} catch (err) {
// Fallback: use simpler dns2 API methods
try {
const response = await this._simpleLookup(domain, recordType);
if (response.answers && response.answers.length > 0) {
result.ttl = response.answers[0].ttl;
for (const answer of response.answers) {
result.records.push(this._parseAnswer(answer));
}
} else {
result.error = `No ${recordType} records found for '${domain}'`;
}
} catch (fallbackErr) {
result.error = fallbackErr.message || String(fallbackErr);
}
}
return result;
}
/**
* Simple lookup using the dns2 resolve method.
*/
async _simpleLookup(domain, recordType) {
const resolve = new dns2({ nameServers: [this.nameserver] });
return resolve.resolve(domain, recordType);
}
/**
* Look up all supported record types for a domain.
* @param {string} domain
* @returns {Promise<Object>}
*/
async lookupAll(domain) {
const results = { domain, results: {} };
for (const rtype of SUPPORTED_RECORD_TYPES) {
const lookupResult = await this.lookup(domain, rtype);
if (lookupResult.records && lookupResult.records.length > 0) {
results.results[rtype] = lookupResult;
}
}
return results;
}
/**
* Perform a reverse DNS lookup for an IP address.
* @param {string} ipAddress
* @returns {Promise<Object>}
*/
async reverseLookup(ipAddress) {
const result = {
ip_address: ipAddress,
hostnames: [],
};
try {
// Build PTR domain from IP
const parts = ipAddress.split('.');
if (parts.length === 4) {
const ptrDomain = parts.reverse().join('.') + '.in-addr.arpa';
result.ptr_domain = ptrDomain;
const lookupResult = await this.lookup(ptrDomain, 'PTR');
if (lookupResult.error) {
result.error = lookupResult.error;
} else {
result.ttl = lookupResult.ttl;
for (const rec of lookupResult.records) {
if (rec.target) {
result.hostnames.push(rec.target);
} else if (rec.data) {
result.hostnames.push(rec.data);
}
}
}
} else {
// IPv6 reverse lookup
const expanded = this._expandIPv6(ipAddress);
const nibbles = expanded.replace(/:/g, '').split('').reverse().join('.');
const ptrDomain = nibbles + '.ip6.arpa';
result.ptr_domain = ptrDomain;
const lookupResult = await this.lookup(ptrDomain, 'PTR');
if (lookupResult.error) {
result.error = lookupResult.error;
} else {
result.ttl = lookupResult.ttl;
for (const rec of lookupResult.records) {
if (rec.target) {
result.hostnames.push(rec.target);
}
}
}
}
} catch (err) {
result.error = err.message || String(err);
}
return result;
}
/**
* Perform a DNS lookup using DNS-over-HTTPS (DoH) via JSON API.
* @param {string} domain
* @param {string} recordType
* @param {string} provider
* @returns {Promise<Object>}
*/
async dohLookup(domain, recordType = 'A', provider = 'google') {
recordType = recordType.toUpperCase();
const dohUrl = DOH_PROVIDERS[provider.toLowerCase()] || provider;
const result = {
domain,
record_type: recordType,
provider,
doh_url: dohUrl,
records: [],
};
try {
// Use JSON API (Google DNS format)
const typeCode = dns2.Packet.TYPE[recordType] || 1;
const url = `${dohUrl}?name=${encodeURIComponent(domain)}&type=${recordType}`;
const responseData = await this._httpsGet(url, {
'Accept': 'application/dns-json',
});
const json = JSON.parse(responseData);
if (json.Status === 3) {
result.error = `Domain '${domain}' does not exist (NXDOMAIN)`;
return result;
}
if (!json.Answer || json.Answer.length === 0) {
result.error = `No ${recordType} records in DoH response`;
return result;
}
result.ttl = json.Answer[0].TTL;
for (const answer of json.Answer) {
const record = {
type: this._typeCodeToString(answer.type),
data: answer.data,
};
// Parse specific record types
if (answer.type === 1 || answer.type === 28) {
record.address = answer.data;
} else if (answer.type === 15) {
const parts = answer.data.split(' ');
record.preference = parseInt(parts[0], 10);
record.exchange = parts[1];
} else if (answer.type === 2) {
record.nameserver = answer.data;
}
result.records.push(record);
}
} catch (err) {
result.error = `DoH lookup error: ${err.message || err}`;
}
return result;
}
/**
* Resolve multiple domains in batch.
* @param {string[]} domains
* @param {string} recordType
* @returns {Promise<Object[]>}
*/
async batchResolve(domains, recordType = 'A') {
const results = [];
for (const domain of domains) {
const trimmed = domain.trim();
if (trimmed) {
const lookupResult = await this.lookup(trimmed, recordType);
results.push(lookupResult);
}
}
return results;
}
/**
* Resolve a batch of mixed queries.
* @param {Array<{domain: string, record_type?: string}>} queries
* @returns {Promise<Object[]>}
*/
async batchResolveMixed(queries) {
const results = [];
for (const query of queries) {
const domain = (query.domain || '').trim();
const recordType = (query.record_type || 'A').trim().toUpperCase();
if (domain) {
const lookupResult = await this.lookup(domain, recordType);
results.push(lookupResult);
}
}
return results;
}
/**
* Parse a DNS answer into a structured object.
*/
_parseAnswer(answer) {
const record = {
type: this._typeCodeToString(answer.type),
name: answer.name,
ttl: answer.ttl,
};
if (answer.address) {
record.address = answer.address;
}
if (answer.data) {
record.data = answer.data;
}
if (answer.exchange) {
record.exchange = answer.exchange;
record.preference = answer.priority || answer.preference;
}
if (answer.ns) {
record.nameserver = answer.ns;
}
if (answer.target) {
record.target = answer.target;
}
if (answer.primary) {
record.mname = answer.primary;
record.rname = answer.admin;
record.serial = answer.serial;
record.refresh = answer.refresh;
record.retry = answer.retry;
record.expire = answer.expire;
record.minimum = answer.minimum;
}
return record;
}
/**
* Convert DNS type code to string.
*/
_typeCodeToString(code) {
const types = {
1: 'A', 2: 'NS', 5: 'CNAME', 6: 'SOA', 12: 'PTR',
15: 'MX', 16: 'TXT', 28: 'AAAA', 33: 'SRV', 257: 'CAA',
};
return types[code] || `TYPE${code}`;
}
/**
* Expand an IPv6 address to full form.
*/
_expandIPv6(ip) {
const groups = ip.split(':');
const expanded = [];
for (const group of groups) {
if (group === '') {
const missing = 8 - groups.filter(g => g !== '').length;
for (let i = 0; i <= missing; i++) {
expanded.push('0000');
}
} else {
expanded.push(group.padStart(4, '0'));
}
}
return expanded.join(':');
}
/**
* Make an HTTPS GET request.
*/
_httpsGet(url, headers = {}) {
return new Promise((resolve, reject) => {
const urlObj = new URL(url);
const client = urlObj.protocol === 'https:' ? https : http;
const req = client.get(url, { headers, timeout: this.timeout }, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(data);
} else {
reject(new Error(`HTTP ${res.statusCode}: ${data}`));
}
});
});
req.on('error', reject);
req.on('timeout', () => {
req.destroy();
reject(new Error('Request timed out'));
});
});
}
}
// ---- Output Formatting ----
function printHeader(text) {
console.log(chalk.bold.blue(`\n${text}`));
console.log(chalk.gray('-'.repeat(40)));
}
function printResult(result) {
const domain = result.domain || 'N/A';
const rtype = result.record_type || 'N/A';
console.log(chalk.bold.yellow(`\n--- ${domain} (${rtype}) ---`));
if (result.error) {
console.log(chalk.red(` Error: ${result.error}`));
return;
}
if (result.ttl !== undefined) {
console.log(chalk.gray(` TTL: ${result.ttl}`));
}
for (const rec of (result.records || [])) {
const type = rec.type || '';
if (type === 'A' || type === 'AAAA') {
console.log(chalk.green(` ${type}: ${rec.address || rec.data}`));
} else if (type === 'MX') {
console.log(chalk.green(` MX: ${rec.exchange || rec.data} (priority: ${rec.preference})`));
} else if (type === 'NS') {
console.log(chalk.green(` NS: ${rec.nameserver || rec.data}`));
} else if (type === 'TXT') {
console.log(chalk.green(` TXT: ${rec.data}`));
} else if (type === 'CNAME') {
console.log(chalk.green(` CNAME: ${rec.target || rec.data}`));
} else if (type === 'SOA') {
console.log(chalk.green(` SOA: mname=${rec.mname}, serial=${rec.serial}`));
} else if (type === 'PTR') {
console.log(chalk.green(` PTR: ${rec.target || rec.data}`));
} else if (type === 'SRV') {
console.log(chalk.green(` SRV: ${rec.target}:${rec.port} (priority=${rec.priority}, weight=${rec.weight})`));
} else {
console.log(chalk.green(` ${type}: ${JSON.stringify(rec)}`));
}
}
}
// ---- Main ----
async function main() {
console.log(chalk.bold.cyan('='.repeat(60)));
console.log(chalk.bold.cyan(' DNS Resolver - Comprehensive DNS Lookup Tool (JavaScript)'));
console.log(chalk.bold.cyan('='.repeat(60)));
const resolver = new DnsResolver({ nameserver: '8.8.8.8' });
// 1. Standard DNS lookups
printHeader('[1] Standard DNS Lookups');
const testDomain = 'google.com';
for (const rtype of ['A', 'AAAA', 'MX', 'NS', 'TXT', 'SOA']) {
const result = await resolver.lookup(testDomain, rtype);
printResult(result);
}
// 2. All record types
printHeader('[2] All Record Types for "example.com"');
const allResults = await resolver.lookupAll('example.com');
for (const [rtype, res] of Object.entries(allResults.results)) {
printResult(res);
}
// 3. Reverse DNS
printHeader('[3] Reverse DNS Lookup');
for (const ip of ['8.8.8.8', '1.1.1.1']) {
const revResult = await resolver.reverseLookup(ip);
console.log(chalk.yellow(`\n IP: ${revResult.ip_address}`));
if (revResult.error) {
console.log(chalk.red(` Error: ${revResult.error}`));
} else {
console.log(chalk.gray(` PTR domain: ${revResult.ptr_domain}`));
for (const hostname of revResult.hostnames) {
console.log(chalk.green(` Hostname: ${hostname}`));
}
}
}
// 4. DNS-over-HTTPS
printHeader('[4] DNS-over-HTTPS (DoH)');
for (const provider of ['google']) {
const dohResult = await resolver.dohLookup('example.com', 'A', provider);
console.log(chalk.yellow(`\n Provider: ${provider} (${dohResult.doh_url})`));
if (dohResult.error) {
console.log(chalk.red(` Error: ${dohResult.error}`));
} else {
for (const rec of dohResult.records) {
console.log(chalk.green(` ${rec.type}: ${rec.address || rec.data}`));
}
}
}
// 5. Batch resolution
printHeader('[5] Batch Resolution');
const batchDomains = ['google.com', 'github.com', 'stackoverflow.com', 'python.org', 'example.com'];
const batchResults = await resolver.batchResolve(batchDomains, 'A');
for (const res of batchResults) {
if (res.error) {
console.log(chalk.red(` ${res.domain}: ${res.error}`));
} else {
const addresses = res.records.map(r => r.address || r.data).join(', ');
console.log(chalk.green(` ${res.domain}: ${addresses}`));
}
}
// 6. Batch mixed queries
printHeader('[6] Batch Mixed Queries');
const mixedQueries = [
{ domain: 'google.com', record_type: 'A' },
{ domain: 'google.com', record_type: 'MX' },
{ domain: 'github.com', record_type: 'AAAA' },
{ domain: 'example.com', record_type: 'NS' },
];
const mixedResults = await resolver.batchResolveMixed(mixedQueries);
for (const res of mixedResults) {
printResult(res);
}
// 7. JSON output
printHeader('[7] JSON Output (google.com A record)');
const jsonResult = await resolver.lookup('google.com', 'A');
console.log(JSON.stringify(jsonResult, null, 2));
console.log(chalk.bold.cyan('\n' + '='.repeat(60)));
console.log(chalk.bold.cyan(' DNS Resolution Complete'));
console.log(chalk.bold.cyan('='.repeat(60)));
}
main().catch(err => {
console.error(chalk.red('Fatal error:'), err);
process.exit(1);
});
module.exports = { DnsResolver };