Skip to content

Commit

Permalink
updated: make type optional for dns resolvers
Browse files Browse the repository at this point in the history
& more tests for CAA, ANY
  • Loading branch information
AndreiIgna committed Jan 27, 2025
1 parent 505055c commit df33a3a
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 45 deletions.
93 changes: 82 additions & 11 deletions src/dns-resolvers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ suite('Cloudflare DNS resolver', () => {
})

test('A records', async () => {
const aRecords = await dnsRecordsCloudflare('cloudflare.com')
const aRecords = await dnsRecordsCloudflare('cloudflare.com', 'A')

assert.notEqual(aRecords.length, 0)
assert.equal(aRecords[0].name, 'cloudflare.com')
Expand Down Expand Up @@ -53,33 +53,84 @@ suite('Cloudflare DNS resolver', () => {
assert.equal(txtRecords[0].type, 'TXT')
assert.ok(Number.isSafeInteger(txtRecords[0].ttl))
assert.ok(txtRecords[0].data)
assert.ok(txtRecords.some(record => record.data.includes('v=spf1')))
})

test('CAA records', async () => {
const caaRecords = await dnsRecordsCloudflare('cloudflare.com', 'CAA')

assert.notEqual(caaRecords.length, 0)
assert.equal(caaRecords[0].name, 'cloudflare.com')
assert.equal(caaRecords[0].type, 'CAA')
assert.ok(Number.isSafeInteger(caaRecords[0].ttl))
assert.ok(caaRecords[0].data)
})

test('ANY records', async () => {
const anyRecords = await dnsRecordsCloudflare('dash.cloudflare.com')

assert.notEqual(anyRecords.length, 0)
assert.equal(anyRecords[0].name, 'dash.cloudflare.com')
assert.equal(anyRecords[0].type, 'A')
assert.ok(Number.isSafeInteger(anyRecords[0].ttl))
assert.ok(isIPv4(anyRecords[0].data))
})
})

suite('Google DNS resolver', () => {
test('A records', async () => {
const aRecords = await dnsRecordsGoogle('google.com')
const aRecords = await dnsRecordsGoogle('gmail.com', 'A')

assert.notEqual(aRecords.length, 0)
assert.equal(aRecords[0].name, 'google.com')
assert.equal(aRecords[0].name, 'gmail.com')
assert.equal(aRecords[0].type, 'A')
assert.ok(Number.isSafeInteger(aRecords[0].ttl))
assert.ok(isIPv4(aRecords[0].data))
})

test('AAAA records', async () => {
const aaaaRecords = await dnsRecordsGoogle('gmail.com', 'AAAA')

assert.notEqual(aaaaRecords.length, 0)
assert.equal(aaaaRecords[0].name, 'gmail.com')
assert.equal(aaaaRecords[0].type, 'AAAA')
assert.ok(Number.isSafeInteger(aaaaRecords[0].ttl))
assert.ok(isIPv6(aaaaRecords[0].data))
})

test('TXT records', async () => {
const txtRecords = await dnsRecordsGoogle('google.com', 'txt')
const txtRecords = await dnsRecordsGoogle('gmail.com', 'txt')

assert.notEqual(txtRecords.length, 0)
assert.equal(txtRecords[0].name, 'google.com')
assert.equal(txtRecords[0].name, 'gmail.com')
assert.equal(txtRecords[0].type, 'TXT')
assert.ok(Number.isSafeInteger(txtRecords[0].ttl))
assert.ok(txtRecords[0].data)
})

test('CAA records', async () => {
const caaRecords = await dnsRecordsGoogle('gmail.com', 'CAA')

assert.notEqual(caaRecords.length, 0)
assert.equal(caaRecords[0].name, 'gmail.com')
assert.equal(caaRecords[0].type, 'CAA')
assert.ok(Number.isSafeInteger(caaRecords[0].ttl))
assert.ok(caaRecords[0].data)
})

test('ANY records', async () => {
const anyRecords = await dnsRecordsGoogle('mail.google.com')

assert.notEqual(anyRecords.length, 0)
assert.equal(anyRecords[0].name, 'mail.google.com')
assert.equal(anyRecords[0].type, 'A')
assert.ok(Number.isSafeInteger(anyRecords[0].ttl))
assert.ok(isIPv4(anyRecords[0].data))
})
})

suite('Node DNS resolver', () => {
test('NS resolver', async () => {
test('NS records', async () => {
const nsRecords = await dnsRecordsNodeDns('nodejs.org', 'NS')

assert.notEqual(nsRecords.length, 0)
Expand All @@ -89,8 +140,8 @@ suite('Node DNS resolver', () => {
assert.ok(nsRecords[0].data.length)
})

test('A resolver', async () => {
const aRecords = await dnsRecordsNodeDns('nodejs.org')
test('A records', async () => {
const aRecords = await dnsRecordsNodeDns('nodejs.org', 'A')

assert.notEqual(aRecords.length, 0)
assert.equal(aRecords[0].name, 'nodejs.org')
Expand All @@ -99,7 +150,7 @@ suite('Node DNS resolver', () => {
assert.ok(isIPv4(aRecords[0].data))
})

test('AAAA resolver', async () => {
test('AAAA records', async () => {
const aaaaRecords = await dnsRecordsNodeDns('nodejs.org', 'AAAA')

assert.notEqual(aaaaRecords.length, 0)
Expand All @@ -109,13 +160,33 @@ suite('Node DNS resolver', () => {
assert.ok(isIPv6(aaaaRecords[0].data))
})

test('TXT resolver', async () => {
const txtRecords = await dnsRecordsNodeDns('nodejs.org', 'txt')
test('TXT records', async () => {
const txtRecords = await dnsRecordsNodeDns('nodejs.org', 'TXT')

assert.notEqual(txtRecords.length, 0)
assert.equal(txtRecords[0].name, 'nodejs.org')
assert.equal(txtRecords[0].type, 'TXT')
assert.ok(Number.isSafeInteger(txtRecords[0].ttl))
assert.ok(txtRecords[0].data)
})

test('CAA records', async () => {
const caaRecords = await dnsRecordsNodeDns('npmjs.com', 'CAA')

assert.notEqual(caaRecords.length, 0)
assert.equal(caaRecords[0].name, 'npmjs.com')
assert.equal(caaRecords[0].type, 'CAA')
assert.ok(Number.isSafeInteger(caaRecords[0].ttl))
assert.ok(caaRecords[0].data)
})

test('ANY records', async () => {
const anyRecords = await dnsRecordsNodeDns('docs.npmjs.com')

assert.notEqual(anyRecords.length, 0)
assert.equal(anyRecords[0].name, 'docs.npmjs.com')
assert.equal(anyRecords[0].type, 'CNAME')
assert.ok(Number.isSafeInteger(anyRecords[0].ttl))
assert.equal(anyRecords[0].data, 'npm.github.io')
})
})
102 changes: 68 additions & 34 deletions src/dns-resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,15 @@ function prepareDnsRecord(record: DnsRecord): DnsRecord {
return record
}

export async function dnsRecordsCloudflare(name: string, type: string = 'A'): Promise<DnsRecord[]> {
const re = await fetch(`https://cloudflare-dns.com/dns-query?name=${name}&type=${type}`, {
export async function dnsRecordsCloudflare(name: string, type?: string): Promise<DnsRecord[]> {
const cloudflareDnsUrl = new URL('https://cloudflare-dns.com/dns-query')
cloudflareDnsUrl.searchParams.set('name', name)

if (type) {
cloudflareDnsUrl.searchParams.set('type', type)
}

const re = await fetch(cloudflareDnsUrl, {
headers: {
accept: 'application/dns-json',
}
Expand All @@ -48,8 +55,15 @@ export async function dnsRecordsCloudflare(name: string, type: string = 'A'): Pr
return records
}

export async function dnsRecordsGoogle(name: string, type: string = 'A'): Promise<DnsRecord[]> {
const re = await fetch(`https://dns.google/resolve?name=${name}&type=${type}`)
export async function dnsRecordsGoogle(name: string, type?: string): Promise<DnsRecord[]> {
const googleDnsUrl = new URL('https://dns.google/resolve')
googleDnsUrl.searchParams.set('name', name)

if (type) {
googleDnsUrl.searchParams.set('type', type)
}

const re = await fetch(googleDnsUrl)

if (!re.ok) {
throw new Error(`Error fetching DNS records for ${name}: ${re.status} ${re.statusText}`)
Expand All @@ -76,7 +90,7 @@ export async function dnsRecordsGoogle(name: string, type: string = 'A'): Promis
* @param server The DNS server to query. If not provided, the default DNS server on the network will be used
* @returns The DNS records
*/
export async function dnsRecordsNodeDig(names: string | string[], types: string | string[] = 'A', server?: string): Promise<DnsRecord[]> {
export async function dnsRecordsNodeDig(names: string | string[], types?: string | string[], server?: string): Promise<DnsRecord[]> {
// start building the arguments list for the `dig` command
const args = []

Expand All @@ -94,11 +108,11 @@ export async function dnsRecordsNodeDig(names: string | string[], types: string
}

names.forEach(name => {
if (Array.isArray(types) && types.length) {
if (Array.isArray(types)) {
types.forEach(type => {
args.push(name, type)
})
} else if (types && typeof types === 'string') {
} else if (typeof types === 'string') {
args.push(name, types)
} else {
args.push(name)
Expand Down Expand Up @@ -142,34 +156,37 @@ export async function dnsRecordsNodeDig(names: string | string[], types: string
* @param types The DNS type to query
* @returns The DNS records
*/
export async function dnsRecordsNodeDns(name: string, type: string = 'A'): Promise<DnsRecord[]> {
export async function dnsRecordsNodeDns(name: string, type?: string): Promise<DnsRecord[]> {
const { promises: dns } = await import('node:dns')
type = type.toUpperCase()

if (type) {
type = type.toUpperCase()
}

const dnsRecords: DnsRecord[] = []

try {
if (['A', 'AAAA'].includes(type)) {
if (!type) {
const foundRecords = await dns.resolveAny(name)

foundRecords.forEach(record => {
if (record.type === 'A') {
dnsRecords.push({ name, type: record.type, ttl: record.ttl, data: record.address })
} else if (record.type === 'CNAME') {
dnsRecords.push({ name, type: record.type, ttl: 0, data: record.value })
}
})
} else if (['A', 'AAAA'].includes(type)) {
const foundRecords = type === 'A' ? await dns.resolve4(name, { ttl: true }) : await dns.resolve6(name, { ttl: true })

foundRecords.forEach(record => {
dnsRecords.push({
name,
type,
ttl: record.ttl,
data: record.address,
})
dnsRecords.push({ name, type, ttl: record.ttl, data: record.address })
})
} else if (type === 'CNAME') {
const foundRecords = await dns.resolveCname(name)

foundRecords.forEach(record => {
dnsRecords.push({
name,
type,
ttl: 0,
data: record,
})
dnsRecords.push({ name, type, ttl: 0, data: record })
})
} else if (type === 'MX') {
const foundRecords = await dns.resolveMx(name)
Expand All @@ -186,12 +203,7 @@ export async function dnsRecordsNodeDns(name: string, type: string = 'A'): Promi
const foundRecords = await dns.resolveNs(name)

foundRecords.forEach(record => {
dnsRecords.push({
name,
type,
ttl: 0,
data: record,
})
dnsRecords.push({ name, type, ttl: 0, data: record })
})
} else if (type === 'SOA') {
const foundRecords = await dns.resolveSoa(name)
Expand All @@ -206,12 +218,34 @@ export async function dnsRecordsNodeDns(name: string, type: string = 'A'): Promi
const foundRecords = await dns.resolveTxt(name)

foundRecords.forEach(record => {
dnsRecords.push({
name,
type,
ttl: 0,
data: record.join(' '),
})
dnsRecords.push({ name, type, ttl: 0, data: record.join(' ') })
})
} else if (type === 'CAA') {
const foundRecords = await dns.resolveCaa(name)

foundRecords.forEach(record => {
let data: string | undefined

if (record.contactemail) {
data = `contactemail "${record.contactemail}"`
} else if (record.contactphone) {
data = `contactphone "${record.contactphone}"`
} else if (record.iodef) {
data = `iodef "${record.iodef}"`
} else if (record.issue) {
data = `issue "${record.issue}"`
} else if (record.issuewild) {
data = `issuewild "${record.issuewild}"`
}

if (data) {
dnsRecords.push({
name,
type,
ttl: 0,
data: `${record.critical} ${data}`,
})
}
})
}
} catch (e) {}
Expand Down

0 comments on commit df33a3a

Please sign in to comment.