diggy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/get-dns-records.d.ts +2 -0
- package/dist/get-dns-records.js +10 -0
- package/dist/get-resolver.d.ts +2 -0
- package/dist/get-resolver.js +18 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/resolvers/dig-resolver.d.ts +2 -0
- package/dist/resolvers/dig-resolver.js +32 -0
- package/dist/resolvers/doh-resolver.d.ts +2 -0
- package/dist/resolvers/doh-resolver.js +42 -0
- package/dist/resolvers/dot-resolver.d.ts +1 -0
- package/dist/resolvers/dot-resolver.js +2 -0
- package/dist/resolvers/node-resolver.d.ts +2 -0
- package/dist/resolvers/node-resolver.js +45 -0
- package/dist/types.d.ts +54 -0
- package/dist/types.js +14 -0
- package/dist/utils/resolve-all-records.d.ts +2 -0
- package/dist/utils/resolve-all-records.js +8 -0
- package/dist/utils/to-dns-record.d.ts +9 -0
- package/dist/utils/to-dns-record.js +53 -0
- package/dist/utils/to-dns-type.d.ts +2 -0
- package/dist/utils/to-dns-type.js +9 -0
- package/package.json +52 -0
- package/readme.md +238 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Roman Ožana <roman@ozana.cz> (https://ozana.cz/)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getResolver } from "./get-resolver";
|
|
2
|
+
import { resolveAllRecords } from "./utils/resolve-all-records";
|
|
3
|
+
import { toDnsType } from "./utils/to-dns-type";
|
|
4
|
+
export function getDnsRecords(host, type, resolver) {
|
|
5
|
+
const dnsResolver = getResolver(resolver);
|
|
6
|
+
const dnsType = toDnsType(type);
|
|
7
|
+
return dnsType
|
|
8
|
+
? dnsResolver(host, dnsType)
|
|
9
|
+
: resolveAllRecords(host, dnsResolver);
|
|
10
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { digResolver } from "./resolvers/dig-resolver";
|
|
2
|
+
import { dohResolver } from "./resolvers/doh-resolver";
|
|
3
|
+
import { nodeResolver } from "./resolvers/node-resolver";
|
|
4
|
+
const resolvers = {
|
|
5
|
+
nodejs: nodeResolver(),
|
|
6
|
+
dig: digResolver(),
|
|
7
|
+
google: dohResolver("https://dns.google/resolve"),
|
|
8
|
+
cloudflare: dohResolver("https://cloudflare-dns.com/dns-query"),
|
|
9
|
+
};
|
|
10
|
+
export function getResolver(resolver) {
|
|
11
|
+
if (typeof resolver === "function") {
|
|
12
|
+
return resolver;
|
|
13
|
+
}
|
|
14
|
+
if (typeof resolver === "string" && resolver in resolvers) {
|
|
15
|
+
return resolvers[resolver];
|
|
16
|
+
}
|
|
17
|
+
return resolvers.google;
|
|
18
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { toDnsRecord } from "../utils/to-dns-record";
|
|
2
|
+
export function digResolver(server) {
|
|
3
|
+
return async (host, type) => {
|
|
4
|
+
const args = [];
|
|
5
|
+
if (server) {
|
|
6
|
+
if (!server.startsWith("@")) {
|
|
7
|
+
server = `@${server}`;
|
|
8
|
+
}
|
|
9
|
+
args.push(server);
|
|
10
|
+
}
|
|
11
|
+
args.push(host, type);
|
|
12
|
+
const { spawnSync } = await import("node:child_process");
|
|
13
|
+
// Use spawnSync to run the dig command synchronously and capture the output
|
|
14
|
+
const dig = spawnSync("dig", [...args, "+noall", "+answer", "+cdflag"]);
|
|
15
|
+
const results = dig.stdout.toString();
|
|
16
|
+
const records = [];
|
|
17
|
+
// split lines & ignore comments or empty lines
|
|
18
|
+
results
|
|
19
|
+
.split("\n")
|
|
20
|
+
.filter((line) => line.length && !line.startsWith(";"))
|
|
21
|
+
.forEach((line) => {
|
|
22
|
+
const parts = line.replace(/\t+/g, " ").split(" ");
|
|
23
|
+
records.push(toDnsRecord({
|
|
24
|
+
name: parts[0] ?? "",
|
|
25
|
+
ttl: Number(parts[1]),
|
|
26
|
+
type: parts[3],
|
|
27
|
+
data: parts.slice(4).join(" "),
|
|
28
|
+
}));
|
|
29
|
+
});
|
|
30
|
+
return records;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { toDnsRecord } from "../utils/to-dns-record";
|
|
2
|
+
const DNSTypeNumbers = new Map([
|
|
3
|
+
[1, "A"],
|
|
4
|
+
[2, "NS"],
|
|
5
|
+
[5, "CNAME"],
|
|
6
|
+
[6, "SOA"],
|
|
7
|
+
[12, "PTR"],
|
|
8
|
+
[15, "MX"],
|
|
9
|
+
[16, "TXT"],
|
|
10
|
+
[24, "SIG"],
|
|
11
|
+
[25, "KEY"],
|
|
12
|
+
[28, "AAAA"],
|
|
13
|
+
[33, "SRV"],
|
|
14
|
+
[35, "NAPTR"],
|
|
15
|
+
[43, "DS"],
|
|
16
|
+
[48, "DNSKEY"],
|
|
17
|
+
[257, "CAA"],
|
|
18
|
+
]);
|
|
19
|
+
export function dohResolver(url) {
|
|
20
|
+
const dnsUrl = new URL(url);
|
|
21
|
+
return async (host, type) => {
|
|
22
|
+
dnsUrl.searchParams.set("name", host);
|
|
23
|
+
dnsUrl.searchParams.set("type", type);
|
|
24
|
+
const re = await fetch(dnsUrl, {
|
|
25
|
+
headers: { accept: "application/dns-json" },
|
|
26
|
+
});
|
|
27
|
+
if (!re.ok) {
|
|
28
|
+
throw new Error(`Error fetching DNS records for ${host}: ${re.status} ${re.statusText}`);
|
|
29
|
+
}
|
|
30
|
+
const json = (await re.json());
|
|
31
|
+
if (!Array.isArray(json.Answer))
|
|
32
|
+
return []; // No records found
|
|
33
|
+
return json.Answer.map((record) => {
|
|
34
|
+
return toDnsRecord({
|
|
35
|
+
name: record.name,
|
|
36
|
+
type: DNSTypeNumbers.get(record.type) ?? "UNKNOWN",
|
|
37
|
+
ttl: record.TTL,
|
|
38
|
+
data: record.data,
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as _dns from "node:dns/promises";
|
|
2
|
+
import { DNSRecordType } from "../types";
|
|
3
|
+
export function nodeResolver(servers = []) {
|
|
4
|
+
const dns = new _dns.Resolver();
|
|
5
|
+
if (servers.length > 0) {
|
|
6
|
+
dns.setServers(servers);
|
|
7
|
+
}
|
|
8
|
+
return async (host, type) => {
|
|
9
|
+
try {
|
|
10
|
+
// Handle special cases for A and AAAA records to include TTL
|
|
11
|
+
if (type === DNSRecordType.A || type === DNSRecordType.AAAA) {
|
|
12
|
+
const records = type === DNSRecordType.A
|
|
13
|
+
? await dns.resolve4(host, { ttl: true })
|
|
14
|
+
: await dns.resolve6(host, { ttl: true });
|
|
15
|
+
return records.map(({ address, ttl }) => ({
|
|
16
|
+
name: host,
|
|
17
|
+
type: type,
|
|
18
|
+
ttl: ttl,
|
|
19
|
+
data: address,
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
// Handle SOA (is not an array)
|
|
23
|
+
if (type === DNSRecordType.SOA) {
|
|
24
|
+
const record = await dns.resolveSoa(host);
|
|
25
|
+
return [
|
|
26
|
+
{
|
|
27
|
+
name: host,
|
|
28
|
+
type: type,
|
|
29
|
+
data: record,
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
// Handle CAA, MX, NAPTR, NS, PTR, SRV, TXT (all return arrays)
|
|
34
|
+
const records = (await dns.resolve(host, type));
|
|
35
|
+
return records.map((record) => ({
|
|
36
|
+
name: host,
|
|
37
|
+
type: type,
|
|
38
|
+
data: Array.isArray(record) ? record.join(" ") : record,
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type DNSResolver = (host: string, type: DNSRecordType) => Promise<AnyDNSRecord[]>;
|
|
2
|
+
export type BuildInDNSResolver = "nodejs" | "dig" | "google" | "cloudflare";
|
|
3
|
+
export declare enum DNSRecordType {
|
|
4
|
+
A = "A",
|
|
5
|
+
AAAA = "AAAA",
|
|
6
|
+
CAA = "CAA",
|
|
7
|
+
CNAME = "CNAME",
|
|
8
|
+
NAPTR = "NAPTR",
|
|
9
|
+
MX = "MX",
|
|
10
|
+
NS = "NS",
|
|
11
|
+
PTR = "PTR",
|
|
12
|
+
SOA = "SOA",
|
|
13
|
+
SRV = "SRV",
|
|
14
|
+
TXT = "TXT"
|
|
15
|
+
}
|
|
16
|
+
export type MxRecordData = {
|
|
17
|
+
exchange: string;
|
|
18
|
+
priority: number;
|
|
19
|
+
};
|
|
20
|
+
export type SoaRecordData = {
|
|
21
|
+
nsname: string;
|
|
22
|
+
hostmaster: string;
|
|
23
|
+
serial: number;
|
|
24
|
+
refresh: number;
|
|
25
|
+
retry: number;
|
|
26
|
+
expire: number;
|
|
27
|
+
minttl: number;
|
|
28
|
+
};
|
|
29
|
+
export type CaaRecordData = {
|
|
30
|
+
flags: number;
|
|
31
|
+
tag: string;
|
|
32
|
+
value: string;
|
|
33
|
+
};
|
|
34
|
+
export type NaptrRecordData = {
|
|
35
|
+
order: number;
|
|
36
|
+
preference: number;
|
|
37
|
+
flags: string;
|
|
38
|
+
service: string;
|
|
39
|
+
regexp: string;
|
|
40
|
+
replacement: string;
|
|
41
|
+
};
|
|
42
|
+
export type SrvRecordData = {
|
|
43
|
+
priority: number;
|
|
44
|
+
weight: number;
|
|
45
|
+
port: number;
|
|
46
|
+
name: string;
|
|
47
|
+
};
|
|
48
|
+
export type DNSRecord<T = string | string[]> = {
|
|
49
|
+
name: string;
|
|
50
|
+
type: DNSRecordType;
|
|
51
|
+
ttl?: number;
|
|
52
|
+
data: T;
|
|
53
|
+
};
|
|
54
|
+
export type AnyDNSRecord = DNSRecord | DNSRecord<MxRecordData> | DNSRecord<SoaRecordData> | DNSRecord<CaaRecordData> | DNSRecord<NaptrRecordData> | DNSRecord<SrvRecordData>;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export var DNSRecordType;
|
|
2
|
+
(function (DNSRecordType) {
|
|
3
|
+
DNSRecordType["A"] = "A";
|
|
4
|
+
DNSRecordType["AAAA"] = "AAAA";
|
|
5
|
+
DNSRecordType["CAA"] = "CAA";
|
|
6
|
+
DNSRecordType["CNAME"] = "CNAME";
|
|
7
|
+
DNSRecordType["NAPTR"] = "NAPTR";
|
|
8
|
+
DNSRecordType["MX"] = "MX";
|
|
9
|
+
DNSRecordType["NS"] = "NS";
|
|
10
|
+
DNSRecordType["PTR"] = "PTR";
|
|
11
|
+
DNSRecordType["SOA"] = "SOA";
|
|
12
|
+
DNSRecordType["SRV"] = "SRV";
|
|
13
|
+
DNSRecordType["TXT"] = "TXT";
|
|
14
|
+
})(DNSRecordType || (DNSRecordType = {}));
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { DNSRecordType } from "../types";
|
|
2
|
+
export async function resolveAllRecords(host, resolver) {
|
|
3
|
+
const allTypes = Object.values(DNSRecordType);
|
|
4
|
+
const records = await Promise.allSettled(allTypes.map((t) => resolver(host, t)));
|
|
5
|
+
return records
|
|
6
|
+
.filter((record) => record.status === "fulfilled")
|
|
7
|
+
.flatMap((record) => record.value);
|
|
8
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DNSRecordType, } from "../types";
|
|
2
|
+
function convertDataByType(type, data) {
|
|
3
|
+
switch (type) {
|
|
4
|
+
case DNSRecordType.SOA: {
|
|
5
|
+
const parts = String(data).split(" ");
|
|
6
|
+
if (parts.length < 7) {
|
|
7
|
+
throw new Error("Invalid SOA record format");
|
|
8
|
+
}
|
|
9
|
+
return {
|
|
10
|
+
nsname: (parts[0] ?? "").replace(/\.$/, ""),
|
|
11
|
+
hostmaster: (parts[1] ?? "").replace(/\.$/, ""),
|
|
12
|
+
serial: parseInt(parts[2] ?? "", 10),
|
|
13
|
+
refresh: parseInt(parts[3] ?? "", 10),
|
|
14
|
+
retry: parseInt(parts[4] ?? "", 10),
|
|
15
|
+
expire: parseInt(parts[5] ?? "", 10),
|
|
16
|
+
minttl: parseInt(parts[6] ?? "", 10),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
case DNSRecordType.MX: {
|
|
20
|
+
const mx = String(data).split(" ");
|
|
21
|
+
if (mx.length < 2) {
|
|
22
|
+
throw new Error("Invalid MX record format");
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
priority: parseInt(mx[0] ?? "", 10),
|
|
26
|
+
exchange: mx.slice(1).join(" ").replace(/\.$/, ""),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
case DNSRecordType.TXT: {
|
|
30
|
+
const txt = String(data) ?? "";
|
|
31
|
+
// Cloudflare or dig returns TXT records as `"rec1" "rec2" "rec3 "` need to be parsed
|
|
32
|
+
if (txt.startsWith('"') && txt.endsWith('"')) {
|
|
33
|
+
const matches = txt.match(/"([^"]*)"/g);
|
|
34
|
+
return matches
|
|
35
|
+
? matches.map((part) => part.replace(/"/g, ""))
|
|
36
|
+
: [];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return Array.isArray(data) ? data.join(" ") : data;
|
|
41
|
+
}
|
|
42
|
+
export function toDnsRecord({ name, type, ttl, data, }) {
|
|
43
|
+
return {
|
|
44
|
+
// remove trailing dot from name
|
|
45
|
+
name: name.replace(/\.$/, ""),
|
|
46
|
+
// ensure type is a valid DNSRecordType
|
|
47
|
+
type: type,
|
|
48
|
+
// default ttl to 0 if not provided
|
|
49
|
+
ttl: ttl ?? 0,
|
|
50
|
+
// convert data based on type
|
|
51
|
+
data: convertDataByType(type, data),
|
|
52
|
+
};
|
|
53
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "diggy",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Multi-backend DNS resolver for Node.js/Browser — supports dig, DNS over HTTPS, and native Node.js DNS.",
|
|
5
|
+
"repository": "git@github.com:OzzyCzech/diggy.git",
|
|
6
|
+
"author": "Roman Ožana <roman@ozana.cz>",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"dns",
|
|
9
|
+
"dig",
|
|
10
|
+
"dns-over-https",
|
|
11
|
+
"DoH",
|
|
12
|
+
"nodejs",
|
|
13
|
+
"browser",
|
|
14
|
+
"dns-resolver",
|
|
15
|
+
"resolver",
|
|
16
|
+
"lookup",
|
|
17
|
+
"dns-client",
|
|
18
|
+
"dns-server",
|
|
19
|
+
"dns-tools",
|
|
20
|
+
"google-dns",
|
|
21
|
+
"cloudflare-dns",
|
|
22
|
+
"dns-over-tls",
|
|
23
|
+
"js-dns"
|
|
24
|
+
],
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"main": "dist/index.js",
|
|
27
|
+
"types": "dist/index.d.ts",
|
|
28
|
+
"type": "module",
|
|
29
|
+
"exports": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "rm -rf dist && tsc",
|
|
38
|
+
"release": "np",
|
|
39
|
+
"prepare": "npm run build",
|
|
40
|
+
"test": "tsc --noEmit && vitest",
|
|
41
|
+
"format": "biome check --write .",
|
|
42
|
+
"format:check": "biome check ."
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@biomejs/biome": "^2.1.4",
|
|
46
|
+
"@types/node": "^24.2.1",
|
|
47
|
+
"np": "^10.2.0",
|
|
48
|
+
"tsx": "^4.20.4",
|
|
49
|
+
"typescript": "^5.9.2",
|
|
50
|
+
"vitest": "^3.2.4"
|
|
51
|
+
}
|
|
52
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# 👾 Diggy
|
|
2
|
+
|
|
3
|
+
👾 **Diggy** is a flexible, multi-backend JavaScript **DNS resolver** for fetching **DNS records**
|
|
4
|
+
with support for various resolution methods including DNS over HTTPS, native `dig` commands, and Node.js built-in DNS
|
|
5
|
+
functionality.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **✨ Multiple DNS backends** - Choose from Google DoH, Cloudflare DoH, Node.js DNS, or native dig command or even
|
|
10
|
+
create your own custom resolver!
|
|
11
|
+
- **🔒 DNS over HTTPS (DoH)** - Secure DNS queries over encrypted connections
|
|
12
|
+
- **⚡ Native dig Support** - Leverage system [DNS tools](https://linux.die.net/man/1/dig) directly from Node.js
|
|
13
|
+
- **🛠️ Node.js Integration** - Use built-in Node.js [DNS functionality](https://nodejs.org/api/dns.html)
|
|
14
|
+
- **📋 Complete Record Support** - Fetch A, AAAA, SOA, CNAME, TXT, MX, SRV, CAA, NAPTR, and more
|
|
15
|
+
- **🚀 Zero Dependencies** - Lightweight with literally no external dependencies
|
|
16
|
+
- **🎯 TypeScript ready** - Full type definitions included
|
|
17
|
+
|
|
18
|
+
## 📦 Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install diggy
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
yarn add diggy
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm add diggy
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
bun add diggy
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 🚀 Quick Start
|
|
37
|
+
|
|
38
|
+
### Basic Usage
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
import { getDnsRecords } from 'diggy';
|
|
42
|
+
|
|
43
|
+
// Fetch all DNS records for a domain
|
|
44
|
+
const allRecords = await getDnsRecords('example.com');
|
|
45
|
+
console.log(allRecords);
|
|
46
|
+
|
|
47
|
+
// Fetch specific record types
|
|
48
|
+
const aRecords = await getDnsRecords('example.com', 'A');
|
|
49
|
+
const txtRecords = await getDnsRecords('example.com', 'TXT');
|
|
50
|
+
const mxRecords = await getDnsRecords('example.com', 'MX');
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### TypeScript Support
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { type AnyDNSRecord, getDnsRecords } from 'diggy';
|
|
57
|
+
|
|
58
|
+
const records: AnyDNSRecord[] = await getDnsRecords('example.com', 'A');
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
function getDnsRecords(
|
|
63
|
+
host: string,
|
|
64
|
+
type?: string,
|
|
65
|
+
resolver?: string | BuildInDNSResolver | DNSResolver,
|
|
66
|
+
): Promise<AnyDNSRecord[]>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Parameters:**
|
|
70
|
+
|
|
71
|
+
- `host` (string): The domain name to query
|
|
72
|
+
- `type` (string, optional): DNS record type (A, AAAA, MX, TXT, etc.). If omitted, returns all available records
|
|
73
|
+
- `resolver` (string | BuildInDNSResolver | DNSResolver, optional): DNS resolver to use
|
|
74
|
+
|
|
75
|
+
**Returns:** Promise resolving to an array of DNS records
|
|
76
|
+
|
|
77
|
+
## 🌐 Available Resolvers
|
|
78
|
+
|
|
79
|
+
### Built-in Resolvers
|
|
80
|
+
|
|
81
|
+
Diggy includes several pre-configured resolvers:
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
// Use Google DNS JSON Over HTTPS
|
|
85
|
+
const records = await getDnsRecords('example.com', 'A', "google");
|
|
86
|
+
|
|
87
|
+
// Use Cloudflare DNS JSON Over HTTPS
|
|
88
|
+
const records = await getDnsRecords('example.com', 'A', "cloudflare");
|
|
89
|
+
|
|
90
|
+
// Use nodejs dns module
|
|
91
|
+
const records = await getDnsRecords('example.com', 'A', "nodejs");
|
|
92
|
+
|
|
93
|
+
// Use dig command
|
|
94
|
+
const records = await getDnsRecords('example.com', 'A', "dig");
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
| Resolver | Description | Environment |
|
|
98
|
+
|--------------|-----------------------------|---------------------------|
|
|
99
|
+
| `google` | Google DNS over HTTPS | Works in Browser |
|
|
100
|
+
| `cloudflare` | Cloudflare DNS over HTTPS | Works in Browser |
|
|
101
|
+
| `nodejs` | Node.js built-in DNS module | Node.js runtime |
|
|
102
|
+
| `dig` | Native dig command | `dig` installed on system |
|
|
103
|
+
|
|
104
|
+
### Configure built-in resolvers
|
|
105
|
+
|
|
106
|
+
Create your own DNS resolver for custom endpoints:
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
import { getDnsRecords, dohResolver } from 'diggy';
|
|
110
|
+
|
|
111
|
+
const customDohResolver = dohResolver("https://custom.dns.provider/resolve");
|
|
112
|
+
const records = await getDnsRecords('example.com', 'TXT', customDohResolver);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
> 💡 **Tip:** Find more public [DoH endpoints here](https://github.com/curl/curl/wiki/DNS-over-HTTPS)
|
|
116
|
+
|
|
117
|
+
Just like with `dohResolver`, you can also use `digResolver` or `nodeResolver` and specify a custom DNS server:
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
import { getDnsRecords, digResolver, nodeResolver } from 'diggy';
|
|
121
|
+
|
|
122
|
+
// Native nodejs dns resolver witg specific DNS server
|
|
123
|
+
const customNodejsResolver = nodeResolver(['8.8.8.8']);
|
|
124
|
+
const records = await getDnsRecords('example.com', 'A', customNodejsResolver);
|
|
125
|
+
|
|
126
|
+
// Native dig command with specific DNS server
|
|
127
|
+
const customDigResolver = digResolver('1.1.1.1');
|
|
128
|
+
const records = await getDnsRecords('example.com', 'A', customDigResolver);
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
> 💡 **Tip:** Find more public [DNS servers here](https://public-dns.info/)
|
|
132
|
+
|
|
133
|
+
You can also **create your own custom resolver** by implementing the `DNSResolver` interface:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
export type DNSResolver = (
|
|
137
|
+
host: string,
|
|
138
|
+
type: DNSRecordType,
|
|
139
|
+
) => Promise<AnyDNSRecord[]>;
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## 📝 Supported Record Types
|
|
143
|
+
|
|
144
|
+
| Type | Description | Example Use Case |
|
|
145
|
+
|-------|------------------------|-------------------------|
|
|
146
|
+
| A | IPv4 address | Website hosting |
|
|
147
|
+
| AAAA | IPv6 address | IPv6 connectivity |
|
|
148
|
+
| CNAME | Canonical name | Domain aliases |
|
|
149
|
+
| MX | Mail exchange | Email routing |
|
|
150
|
+
| TXT | Text records | SPF, DKIM, verification |
|
|
151
|
+
| SOA | Start of authority | Zone information |
|
|
152
|
+
| SRV | Service records | Service discovery |
|
|
153
|
+
| CAA | Certificate authority | SSL/TLS security |
|
|
154
|
+
| NAPTR | Name authority pointer | ENUM, SIP routing |
|
|
155
|
+
|
|
156
|
+
## 📜 Response Format
|
|
157
|
+
|
|
158
|
+
DNS records are returned as an array of objects with the following structure:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { CaaRecordData, MxRecordData, SoaRecordData, SrvRecordData, NaptrRecordData } from "./types";
|
|
162
|
+
|
|
163
|
+
interface AnyDNSRecord {
|
|
164
|
+
name: string; // Domain name
|
|
165
|
+
type: string; // Record type (A, AAAA, MX, etc.)
|
|
166
|
+
ttl: number; // Time-to-live in seconds
|
|
167
|
+
|
|
168
|
+
// Record data (format varies by type)
|
|
169
|
+
data:
|
|
170
|
+
| string
|
|
171
|
+
| string[]
|
|
172
|
+
| MxRecordData
|
|
173
|
+
| SoaRecordData
|
|
174
|
+
| CaaRecordData
|
|
175
|
+
| NaptrRecordData
|
|
176
|
+
| SrvRecordData;
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Example Response
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
[
|
|
184
|
+
{
|
|
185
|
+
"name": "example.com",
|
|
186
|
+
"type": "SOA",
|
|
187
|
+
"ttl": 3600,
|
|
188
|
+
"data": {
|
|
189
|
+
"nsname": "ns1.example.com.",
|
|
190
|
+
"hostmaster": "hostmaster.example.com.",
|
|
191
|
+
"serial": 2025051204,
|
|
192
|
+
"refresh": 10800,
|
|
193
|
+
"retry": 3600,
|
|
194
|
+
"expire": 604800,
|
|
195
|
+
"minttl": 3600
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"name": "example.cz",
|
|
200
|
+
"type": "A",
|
|
201
|
+
"ttl": 1800,
|
|
202
|
+
"data": "66.33.66.33"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"name": "example.cz",
|
|
206
|
+
"type": "MX",
|
|
207
|
+
"ttl": 60,
|
|
208
|
+
"data": {
|
|
209
|
+
"priority": 10,
|
|
210
|
+
"exchange": "mail.example.com"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## 🔧 Requirements
|
|
217
|
+
|
|
218
|
+
- **Node.js**: Version 14 or higher
|
|
219
|
+
- **dig command**: Required only when using the 'dig' resolver
|
|
220
|
+
- **Internet connection**: Required for DoH resolvers (google, cloudflare)
|
|
221
|
+
|
|
222
|
+
## 📄 License
|
|
223
|
+
|
|
224
|
+
[MIT License](LICENSE) - see the [LICENSE](LICENSE) file for details.
|
|
225
|
+
|
|
226
|
+
## 🤝 Contributing
|
|
227
|
+
|
|
228
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
229
|
+
|
|
230
|
+
1. Fork the repository
|
|
231
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
232
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
233
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
234
|
+
5. Open a Pull Request
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
Made with ❤️ by the [Roman Ožana](https://ozana.cz)
|