Skip to content

Commit

Permalink
updated: get DNS records with dig cmd
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreiIgna committed Mar 11, 2024
1 parent f95bbd6 commit de9424b
Show file tree
Hide file tree
Showing 14 changed files with 141 additions and 54 deletions.
37 changes: 34 additions & 3 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,41 @@
import type { DnsRecord } from './types.js';
export declare function getDnsRecords(name: string, type?: string, resolver?: string): Promise<DnsRecord[]>;
export type DnsRecord = {
name: string;
type: string;
ttl: number;
data: string;
};
/**
* Get DNS records of a given type for a FQDN.
* @param name Fully qualified domain name.
* @param type DNS record type: A, AAAA, TXT, CNAME, MX, etc.
* @param resolver DNS resolver to use. Default: cloudflare-dns.
*/
export declare function getDnsRecords(name: string, type?: string, resolver?: string | Function): Promise<DnsRecord[]>;
export type GetAllDnsRecordsOptions = {
resolver?: string;
resolver?: string | Function;
subdomains?: string[];
};
/**
* Discover all DNS records for a given domain and stream each record as a text line.
* @param domain Valid domain name.
* @param options Options for DNS resolver, extra subdomains to check, etc.
*/
export declare function getAllDnsRecordsStream(domain: string, options?: Partial<GetAllDnsRecordsOptions>): ReadableStream;
/**
* Discover all DNS records for a given domain and return an array of records.
* @param domain Valid domain name.
* @param options Options for DNS resolver, extra subdomains to check, etc.
*/
export declare function getAllDnsRecords(domain: string, options?: Partial<GetAllDnsRecordsOptions>): Promise<DnsRecord[]>;
/**
* Parse a DNS record string into a DnsRecord object.
* @param record DNS record string.
*/
export declare function parseDnsRecord(record: string | Uint8Array): DnsRecord;
/**
* Detect wildcard DNS records and return a new array with the wildcard records added.
* @param domain Domain name.
* @param records Array of DNS records.
* @param percent Percentage of records with the same data to consider a wildcard.
*/
export declare function detectWildcardRecords(domain: string, records: DnsRecord[], percent?: number): DnsRecord[];
33 changes: 30 additions & 3 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,33 @@ const dnsResolvers = {
return records;
},
};
/**
* Get DNS records of a given type for a FQDN.
* @param name Fully qualified domain name.
* @param type DNS record type: A, AAAA, TXT, CNAME, MX, etc.
* @param resolver DNS resolver to use. Default: cloudflare-dns.
*/
export async function getDnsRecords(name, type = 'A', resolver = 'cloudflare-dns') {
if (!isDomain(name)) {
throw new Error(`"${name}" is not a valid domain name`);
}
if (resolver in dnsResolvers) {
if (typeof resolver === 'string' && resolver in dnsResolvers) {
const fn = dnsResolvers[resolver];
if (typeof fn !== 'function') {
throw new Error(`Invalid DNS resolver: ${resolver}`);
}
return fn(name, type);
}
else {
throw new Error(`Invalid DNS resolver: ${resolver}`);
if (typeof resolver === 'function') {
return resolver(name, type);
}
throw new Error(`Invalid DNS resolver: ${resolver}`);
}
/**
* Discover all DNS records for a given domain and stream each record as a text line.
* @param domain Valid domain name.
* @param options Options for DNS resolver, extra subdomains to check, etc.
*/
export function getAllDnsRecordsStream(domain, options = {}) {
options = {
resolver: 'cloudflare-dns',
Expand Down Expand Up @@ -186,6 +198,11 @@ export function getAllDnsRecordsStream(domain, options = {}) {
});
return readable;
}
/**
* Discover all DNS records for a given domain and return an array of records.
* @param domain Valid domain name.
* @param options Options for DNS resolver, extra subdomains to check, etc.
*/
export async function getAllDnsRecords(domain, options = {}) {
const records = [];
const dnsRecordsStream = getAllDnsRecordsStream(domain, options);
Expand All @@ -205,6 +222,10 @@ export async function getAllDnsRecords(domain, options = {}) {
read();
});
}
/**
* Parse a DNS record string into a DnsRecord object.
* @param record DNS record string.
*/
export function parseDnsRecord(record) {
if (record instanceof Uint8Array) {
record = new TextDecoder().decode(record);
Expand All @@ -220,6 +241,12 @@ export function parseDnsRecord(record) {
data: String(parts[4]),
};
}
/**
* Detect wildcard DNS records and return a new array with the wildcard records added.
* @param domain Domain name.
* @param records Array of DNS records.
* @param percent Percentage of records with the same data to consider a wildcard.
*/
export function detectWildcardRecords(domain, records, percent = 0.15) {
const sameDataGroup = {};
const wildcardsFound = [];
Expand Down
2 changes: 1 addition & 1 deletion dist/resolver-node-dig.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DnsRecord } from './types.js';
import { DnsRecord } from './index.js';
/**
* Get DNS records using the `dig` command
*/
Expand Down
10 changes: 7 additions & 3 deletions dist/resolver-node-dig.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { toASCII } from 'punycode';
import url from 'node:url';
const { spawnSync } = await import('node:child_process');
/**
* Get DNS records using the `dig` command
Expand All @@ -17,7 +17,7 @@ export async function getDnsRecordsDig(names, types = 'A', server) {
names = [names];
}
names.forEach(name => {
name = toASCII(name);
name = url.domainToASCII(name);
if (Array.isArray(types) && types.length) {
types.forEach(type => {
args.push(name, type);
Expand All @@ -43,8 +43,12 @@ export async function getDnsRecordsDig(names, types = 'A', server) {
.forEach(line => {
// replace tab(s) with space, then split by space
const parts = line.replace(/[\t]+/g, " ").split(" ");
let name = String(parts[0]);
if (name.endsWith('.')) {
name = name.slice(0, -1);
}
dnsRecords.push({
name: String(parts[0]),
name,
ttl: Number(parts[1]),
type: String(parts[3]),
data: parts.slice(4).join(" ")
Expand Down
6 changes: 0 additions & 6 deletions dist/types.d.ts

This file was deleted.

1 change: 0 additions & 1 deletion dist/types.js

This file was deleted.

11 changes: 11 additions & 0 deletions examples/all-dns-records-node-dig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { DnsRecord, getAllDnsRecords } from '../src/index.ts'
import { getDnsRecordsDig } from '../src/resolver-node-dig.ts'

const domain = 'render.com'

const dnsRecords = await getAllDnsRecords(domain, {
resolver: getDnsRecordsDig,
})

console.log(dnsRecords)
console.log(`${dnsRecords.length} DNS Records found ${domain} 👆`)
3 changes: 2 additions & 1 deletion examples/txt-records-with-dig.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DnsRecord, getDnsRecords } from '../src/index.ts'
import { getDnsRecordsDig } from '../src/resolver-node-dig.ts'

const domain = 'amazon.com'

const txtRecords = await getDnsRecords(domain, 'TXT', 'node-dig')
const txtRecords = await getDnsRecordsDig(domain, 'TXT')

console.log(`TXT records for ${domain}`)
console.log(txtRecords)
2 changes: 1 addition & 1 deletion jsr.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@layered/dns-records",
"version": "2.0.1",
"version": "2.0.2",
"exports": "./src/index.ts"
}
28 changes: 14 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@layered/dns-records",
"version": "2.0.0-beta.8",
"version": "2.0.0-beta.9",
"description": "Discover publicly available DNS Records for a domain",
"type": "module",
"keywords": [
Expand Down
39 changes: 30 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { toASCII } from 'punycode'
import { subdomainsRecords } from './subdomains.js'
import type { DnsRecord } from './types.js'

export type DnsRecord = {
name: string
type: string
ttl: number
data: string
}

const isTld = (tld: string): boolean => {
if (tld.startsWith('.')) {
Expand Down Expand Up @@ -84,37 +90,40 @@ const dnsResolvers: { [key: string]: Function } = {
}

/**
* Get all DNS records of a given type for a FQDN.
* Get DNS records of a given type for a FQDN.
* @param name Fully qualified domain name.
* @param type DNS record type: A, AAAA, TXT, CNAME, MX, etc.
* @param resolver DNS resolver to use. Default: cloudflare-dns.
*/
export async function getDnsRecords(name: string, type: string = 'A', resolver: string = 'cloudflare-dns'): Promise<DnsRecord[]> {
export async function getDnsRecords(name: string, type: string = 'A', resolver: string|Function = 'cloudflare-dns'): Promise<DnsRecord[]> {
if (!isDomain(name)) {
throw new Error(`"${name}" is not a valid domain name`)
}

if (resolver in dnsResolvers) {
if (typeof resolver === 'string' && resolver in dnsResolvers) {
const fn = dnsResolvers[resolver]

if (typeof fn !== 'function') {
throw new Error(`Invalid DNS resolver: ${resolver}`)
}

return fn(name, type)
} else {
throw new Error(`Invalid DNS resolver: ${resolver}`)
} if (typeof resolver === 'function') {
return resolver(name, type)
}

throw new Error(`Invalid DNS resolver: ${resolver}`)
}

export type GetAllDnsRecordsOptions = {
resolver?: string
resolver?: string|Function
subdomains?: string[]
}

/**
* Discover all DNS records for a given domain and return a readable stream. Each record is a text line.
* Discover all DNS records for a given domain and stream each record as a text line.
* @param domain Valid domain name.
* @param options Options for DNS resolver, extra subdomains to check, etc.
*/
export function getAllDnsRecordsStream(domain: string, options: Partial<GetAllDnsRecordsOptions> = {}): ReadableStream {
options = {
Expand Down Expand Up @@ -242,9 +251,11 @@ export function getAllDnsRecordsStream(domain: string, options: Partial<GetAllDn

return readable
}

/**
* Discover and return all DNS records for a given domain.
* Discover all DNS records for a given domain and return an array of records.
* @param domain Valid domain name.
* @param options Options for DNS resolver, extra subdomains to check, etc.
*/
export async function getAllDnsRecords(domain: string, options: Partial<GetAllDnsRecordsOptions> = {}): Promise<DnsRecord[]> {
const records: DnsRecord[] = []
Expand All @@ -268,6 +279,10 @@ export async function getAllDnsRecords(domain: string, options: Partial<GetAllDn
})
}

/**
* Parse a DNS record string into a DnsRecord object.
* @param record DNS record string.
*/
export function parseDnsRecord(record: string|Uint8Array): DnsRecord {
if (record instanceof Uint8Array) {
record = new TextDecoder().decode(record)
Expand All @@ -287,6 +302,12 @@ export function parseDnsRecord(record: string|Uint8Array): DnsRecord {
}
}

/**
* Detect wildcard DNS records and return a new array with the wildcard records added.
* @param domain Domain name.
* @param records Array of DNS records.
* @param percent Percentage of records with the same data to consider a wildcard.
*/
export function detectWildcardRecords(domain: string, records: DnsRecord[], percent = 0.15): DnsRecord[] {
const sameDataGroup: { [key: string]: number } = {}
const wildcardsFound: string[] = []
Expand Down
14 changes: 10 additions & 4 deletions src/resolver-node-dig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { toASCII } from 'punycode'
import url from 'node:url'
const { spawnSync } = await import('node:child_process')
import { DnsRecord } from './types.js'
import { DnsRecord } from './index.js'

/**
* Get DNS records using the `dig` command
Expand All @@ -23,7 +23,7 @@ export async function getDnsRecordsDig(names: string | string[], types: string |
}

names.forEach(name => {
name = toASCII(name)
name = url.domainToASCII(name)

if (Array.isArray(types) && types.length) {
types.forEach(type => {
Expand Down Expand Up @@ -53,8 +53,14 @@ export async function getDnsRecordsDig(names: string | string[], types: string |
// replace tab(s) with space, then split by space
const parts = line.replace(/[\t]+/g, " ").split(" ")

let name = String(parts[0])

if (name.endsWith('.')) {
name = name.slice(0, -1)
}

dnsRecords.push({
name: String(parts[0]),
name,
ttl: Number(parts[1]),
type: String(parts[3]),
data: parts.slice(4).join(" ")
Expand Down
Loading

0 comments on commit de9424b

Please sign in to comment.