1 | import {Resolver} from "node:dns/promises";
|
2 | import ipPtr from "ip-ptr";
|
3 | import pMap from "p-map";
|
4 |
|
5 |
|
6 |
|
7 | const 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 |
|
19 | async 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 |
|
42 | export 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 |
|
51 | export 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 | }
|