UNPKG

2.19 kBJavaScriptView Raw
1import {Resolver} from "node:dns/promises";
2import ipPtr from "ip-ptr";
3import pMap from "p-map";
4
5// using dns.opendns.com because popuplar resolvers could be rate-limited by the
6// blacklist providers, spamhaus being the prime example.
7const defaults = {
8 timeout: 5000,
9 servers: [
10 "208.67.220.220",
11 "208.67.222.222",
12 "2620:119:35::35",
13 "2620:119:53::53",
14 ],
15 concurrency: 64,
16 includeTxt: false,
17};
18
19async function query(addr, blacklist, resolver, opts = {}) {
20 const name = `${ipPtr(addr).replace(/\.i.+/, "")}.${blacklist}`;
21
22 const timeout = setTimeout(() => {
23 resolver.cancel();
24 return opts.includeTxt ? {listed: false, txt: []} : false;
25 }, opts.timeout);
26
27 try {
28 const [addrs, txt] = await Promise.all([
29 resolver.resolve4(name),
30 opts.includeTxt && resolver.resolveTxt(name),
31 ]);
32
33 clearTimeout(timeout);
34
35 const listed = Boolean(addrs.length);
36 return opts.includeTxt ? {listed, txt} : listed;
37 } catch {
38 return opts.includeTxt ? {listed: false, txt: []} : false;
39 }
40}
41
42export async function lookup(addr, blacklist, opts = {}) {
43 opts = {...defaults, ...opts};
44 const resolver = new Resolver();
45 if (opts.servers) {
46 resolver.setServers(Array.isArray(opts.servers) ? opts.servers : [opts.servers]);
47 }
48 return query(addr, blacklist, resolver, opts);
49}
50
51export async function batch(addrs, lists, opts = {}) {
52 opts = {...defaults, ...opts};
53
54 const resolver = new Resolver();
55 if (opts.servers) {
56 resolver.setServers(Array.isArray(opts.servers) ? opts.servers : [opts.servers]);
57 }
58
59 const items = [];
60 for (const address of (Array.isArray(addrs) ? addrs : [addrs])) {
61 for (const blacklist of (Array.isArray(lists) ? lists : [lists])) {
62 items.push({blacklist, address, resolver});
63 }
64 }
65
66 const results = await pMap(items, item => {
67 return query(item.address, item.blacklist, item.resolver, opts);
68 }, {concurrency: opts.concurrency});
69
70 return items.map((item, i) => {
71 if (opts.includeTxt) {
72 item.listed = results[i].listed;
73 item.txt = results[i].txt;
74 } else {
75 item.listed = results[i];
76 }
77 delete item.resolver;
78 return item;
79 });
80}