← All tasks
javascriptcodex/javascript-t1 #26Not a task: already works

DNS Resolver (javascript, written by Codex)

envgap__codex__javascript-t1-26

Written by a coding agent; not on GitHubWritten 2026-03-03

01 / FAILURE SIGNATURE

As the study recorded it

None
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

codex/javascript-t1 #26 · read the task the agent was given
Codex 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

4 files, exactly as written, before any repair.

package-lock.json
{
  "name": "dns-resolver",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "dns-resolver",
      "version": "1.0.0",
      "dependencies": {
        "p-limit": "5.0.0"
      },
      "engines": {
        "node": ">=20.0.0"
      }
    },
    "node_modules/p-limit": {
      "version": "5.0.0"
    }
  }
}
package.json
{
  "name": "dns-resolver",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "main": "src/index.js",
  "scripts": {
    "start": "node src/index.js"
  },
  "engines": {
    "node": ">=20.0.0"
  },
  "dependencies": {
    "p-limit": "5.0.0"
  }
}
README.md
# DNS Resolver (JavaScript)

Performs DNS lookups with multi-type queries, reverse lookup, optional DoH, batch file input, per-query response timing, optional trace output, concurrent resolution, and JSON report export.

## Requirements

- Ubuntu 22.04
- Node.js 20+ (LTS)

## Dependency (Pinned)

- `p-limit@5.0.0`

## Setup

```bash
npm install
```

## Run

```bash
node src/index.js example.com
node src/index.js example.com --type A,AAAA,MX,TXT
node src/index.js --all example.com
node src/index.js 8.8.8.8 --reverse
node src/index.js example.com --server 1.1.1.1
node src/index.js example.com --doh cloudflare --type A,AAAA
node src/index.js --file domains.txt --parallel --threads 20 --type A
node src/index.js example.com --trace --output dns_results.json
node src/index.js
```

## Notes

- Supported types: `A, AAAA, MX, NS, TXT, CNAME, SOA, PTR, SRV`.
- `--all` queries common types in one run.
- If no domain is provided, resolver queries `example.com`, `google.com`, `github.com`, and `cloudflare.com`.
src/index.js
import fs from "fs";
import path from "path";
import dns from "dns/promises";
import pLimit from "p-limit";

const DEFAULT_DOMAINS = ["example.com", "google.com", "github.com", "cloudflare.com"];
const COMMON_TYPES = ["A", "AAAA", "MX", "NS", "TXT", "CNAME", "SOA", "PTR", "SRV"];
const DOH_PROVIDERS = {
  google: "https://dns.google/resolve",
  cloudflare: "https://cloudflare-dns.com/dns-query",
  quad9: "https://dns.quad9.net:5053/dns-query",
};

function parseArgs(argv) {
  const options = {};
  const positional = [];
  for (let i = 0; i < argv.length; i += 1) {
    const t = argv[i];
    if (t.startsWith("--")) {
      const k = t.slice(2);
      const n = argv[i + 1];
      if (n && !n.startsWith("--")) {
        options[k] = n;
        i += 1;
      } else options[k] = true;
    } else positional.push(t);
  }
  return { options, positional };
}

function parseTypes(options) {
  if (options.all) return COMMON_TYPES;
  const raw = String(options.type || "A");
  return raw.split(",").map((s) => s.trim().toUpperCase()).filter(Boolean);
}

function parseDomains(options, positional) {
  const domains = [];
  if (positional[0]) domains.push(positional[0]);
  if (options.file) {
    const lines = fs.readFileSync(path.resolve(String(options.file)), "utf8").split(/\r?\n/).map((x) => x.trim()).filter(Boolean);
    domains.push(...lines);
  }
  if (domains.length === 0) domains.push(...DEFAULT_DOMAINS);
  return [...new Set(domains)];
}

function ptrNameFromIp(ip) {
  if (ip.includes(":")) {
    const expanded = ip.toLowerCase().replace(/:/g, "").padStart(32, "0");
    return `${expanded.split("").reverse().join(".")}.ip6.arpa`;
  }
  return `${ip.split(".").reverse().join(".")}.in-addr.arpa`;
}

async function querySystem(resolver, domain, type, reverseMode) {
  const start = Date.now();
  try {
    let values = [];
    let ttls = [];
    if (reverseMode) {
      values = await resolver.reverse(domain);
      ttls = values.map(() => null);
    } else if (type === "A") {
      const a = await resolver.resolve4(domain, { ttl: true });
      values = a.map((x) => x.address);
      ttls = a.map((x) => x.ttl ?? null);
    } else if (type === "AAAA") {
      const a = await resolver.resolve6(domain, { ttl: true });
      values = a.map((x) => x.address);
      ttls = a.map((x) => x.ttl ?? null);
    } else if (type === "MX") {
      const mx = await resolver.resolveMx(domain);
      values = mx.map((m) => `${m.exchange} (priority=${m.priority})`);
      ttls = values.map(() => null);
    } else if (type === "NS") {
      values = await resolver.resolveNs(domain);
      ttls = values.map(() => null);
    } else if (type === "TXT") {
      const txt = await resolver.resolveTxt(domain);
      values = txt.map((r) => r.join(""));
      ttls = values.map(() => null);
    } else if (type === "CNAME") {
      values = await resolver.resolveCname(domain);
      ttls = values.map(() => null);
    } else if (type === "SOA") {
      const soa = await resolver.resolveSoa(domain);
      values = [JSON.stringify(soa)];
      ttls = [null];
    } else if (type === "PTR") {
      values = await resolver.resolvePtr(domain);
      ttls = values.map(() => null);
    } else if (type === "SRV") {
      const srv = await resolver.resolveSrv(domain);
      values = srv.map((s) => `${s.name}:${s.port} p=${s.priority} w=${s.weight}`);
      ttls = values.map(() => null);
    } else {
      throw new Error(`Unsupported type: ${type}`);
    }
    const ms = Date.now() - start;
    return values.map((v, i) => ({
      domain,
      type,
      value: v,
      ttl: ttls[i],
      response_ms: ms,
      nameserver: resolver.getServers().join(","),
      error: "",
    }));
  } catch (e) {
    return [{
      domain,
      type,
      value: "",
      ttl: null,
      response_ms: Date.now() - start,
      nameserver: resolver.getServers().join(","),
      error: e instanceof Error ? e.message : String(e),
    }];
  }
}

async function queryDoh(provider, domain, type) {
  const base = DOH_PROVIDERS[provider] || provider;
  const start = Date.now();
  try {
    const url = `${base}?name=${encodeURIComponent(domain)}&type=${encodeURIComponent(type)}`;
    const res = await fetch(url, { headers: { accept: "application/dns-json" } });
    if (!res.ok) throw new Error(`DoH HTTP ${res.status}`);
    const data = await res.json();
    const ms = Date.now() - start;
    if (data.Status && data.Status !== 0) {
      return [{
        domain, type, value: "", ttl: null, response_ms: ms, nameserver: `doh:${provider}`,
        error: `DoH status ${data.Status}`,
      }];
    }
    const answers = Array.isArray(data.Answer) ? data.Answer : [];
    if (answers.length === 0) {
      return [{
        domain, type, value: "", ttl: null, response_ms: ms, nameserver: `doh:${provider}`, error: "NoAnswer",
      }];
    }
    return answers.map((a) => ({
      domain,
      type,
      value: a.data,
      ttl: a.TTL ?? null,
      response_ms: ms,
      nameserver: `doh:${provider}`,
      error: "",
    }));
  } catch (e) {
    return [{
      domain, type, value: "", ttl: null, response_ms: Date.now() - start, nameserver: `doh:${provider}`,
      error: e instanceof Error ? e.message : String(e),
    }];
  }
}

async function traceDomain(resolver, domain) {
  const labels = domain.split(".");
  const steps = [];
  for (let i = 0; i < labels.length; i += 1) {
    const zone = labels.slice(i).join(".");
    try {
      const ns = await resolver.resolveNs(zone);
      steps.push({ zone, ns: ns.slice(0, 8) });
    } catch (e) {
      steps.push({ zone, error: e instanceof Error ? e.message : String(e) });
    }
  }
  return steps;
}

function printRows(rows) {
  console.log("Domain | Type | Value | TTL | Response(ms) | Nameserver | Error");
  console.log("------ | ---- | ----- | --- | ------------ | ---------- | -----");
  for (const r of rows) {
    console.log(`${r.domain} | ${r.type} | ${r.value || ""} | ${r.ttl ?? ""} | ${r.response_ms} | ${r.nameserver} | ${r.error || ""}`);
  }
}

async function main() {
  const { options, positional } = parseArgs(process.argv.slice(2));
  const types = parseTypes(options);
  const domains = parseDomains(options, positional);
  const reverseMode = Boolean(options.reverse);
  const parallel = Boolean(options.parallel);
  const threads = Math.max(1, Number(options.threads ?? 10));

  const resolver = new dns.Resolver();
  if (options.server) resolver.setServers([String(options.server)]);

  const tasks = [];
  for (const d of domains) {
    const name = reverseMode ? (options.doh ? ptrNameFromIp(d) : d) : d;
    const qTypes = reverseMode && !options.doh ? ["PTR"] : types;
    for (const t of qTypes) tasks.push({ input: d, domain: name, type: t });
  }

  const limit = pLimit(parallel ? threads : 1);
  const rows = [];
  await Promise.all(tasks.map((task) => limit(async () => {
    const out = options.doh
      ? await queryDoh(String(options.doh), task.domain, task.type)
      : await querySystem(resolver, task.domain, task.type, reverseMode && task.type === "PTR");
    for (const r of out) {
      r.domain = task.input;
      rows.push(r);
      console.log(`${r.domain} ${r.type} -> ${r.value || r.error}`);
    }
  })));

  rows.sort((a, b) => `${a.domain}:${a.type}:${a.value}`.localeCompare(`${b.domain}:${b.type}:${b.value}`));
  printRows(rows);

  const traces = {};
  if (options.trace) {
    for (const d of domains) traces[d] = await traceDomain(resolver, d);
    console.log("\nTrace:");
    for (const [d, t] of Object.entries(traces)) {
      console.log(`- ${d}`);
      for (const step of t) console.log(`  ${step.zone}: ${step.ns ? step.ns.join(", ") : step.error}`);
    }
  }

  const out = path.resolve(String(options.output || "dns_results.json"));
  fs.writeFileSync(out, `${JSON.stringify({
    generated_at: new Date().toISOString(),
    options,
    results: rows,
    traces: options.trace ? traces : undefined,
  }, null, 2)}\n`, "utf8");
  console.log(`\nSaved: ${out}`);
}

main().catch((e) => {
  console.error(`Error: ${e instanceof Error ? e.message : String(e)}`);
  process.exit(1);
});