uptimeify-dnsbl 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/README.md +146 -0
- package/examples/test.js +116 -0
- package/package.json +25 -0
- package/src/definitions.js +459 -0
- package/src/index.d.ts +65 -0
- package/src/index.js +163 -0
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# uptimeify-dnsbl
|
|
2
|
+
|
|
3
|
+
A lightweight, purely functional helper for checking if an IP is blocklisted. We handle the math and the mapping, you handle the network.
|
|
4
|
+
|
|
5
|
+
## What is this?
|
|
6
|
+
|
|
7
|
+
Checking DNS blocklists (DNSBL/RBL) usually involves three annoying steps:
|
|
8
|
+
|
|
9
|
+
1. Reversing the IP address (e.g. `1.2.3.4` -> `4.3.2.1` or the complex IPv6 nibble format).
|
|
10
|
+
2. Knowing which lists to check and what their specific return codes mean.
|
|
11
|
+
3. Making the DNS queries.
|
|
12
|
+
|
|
13
|
+
**uptimeify-dnsbl** solves #1 and #2. We give you the exact domains to query and parse the confusing result codes (like `127.0.0.4`) into human-readable reasons.
|
|
14
|
+
|
|
15
|
+
We intentionally **do not** perform the DNS lookups internally. This allows you to use your preferred DNS resolver, manage timeouts, handle concurrency, and cache results exactly how your app needs it.
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
- **IPv4 & IPv6 Support**: Correctly handles IP reversal for both protocols.
|
|
20
|
+
- **Result Parsing**: Translates cryptic return codes (`127.0.0.2`, `127.0.0.10`) into actual messages ("Listed in SBL", "ISP Policy").
|
|
21
|
+
- **Delisting Links**: Provides direct URLs to removal forms when available.
|
|
22
|
+
- **Zero Dependencies**: Just pure Javascript logic.
|
|
23
|
+
|
|
24
|
+
## Included Lists
|
|
25
|
+
|
|
26
|
+
We maintain definitions for the most reliable and widely used lists:
|
|
27
|
+
|
|
28
|
+
- **Spamhaus ZEN** (SBL, CSS, XBL, PBL) - _The gold standard_
|
|
29
|
+
- **Barracuda** (BRBL)
|
|
30
|
+
- **SpamCop**
|
|
31
|
+
- **Abusix Mail Intelligence**
|
|
32
|
+
- **SORBS** (Aggregate)
|
|
33
|
+
- **UCEPROTECT** (Level 1)
|
|
34
|
+
- **Hostkarma**
|
|
35
|
+
- **Backscatterer**
|
|
36
|
+
- **Invaluement SIP**
|
|
37
|
+
- **SpamCannibal**
|
|
38
|
+
- **DroneBL**
|
|
39
|
+
- **Spam Eating Monkey** (SEM-BLACK)
|
|
40
|
+
- **URIBL Black**
|
|
41
|
+
- **Madavi DNSBL**
|
|
42
|
+
- **RV-SOFT Technology**
|
|
43
|
+
- **ZapBL**
|
|
44
|
+
- **Suomispam Reputation**
|
|
45
|
+
- **Kempt.net**
|
|
46
|
+
- **Korea Services**
|
|
47
|
+
- **NiX Spam**
|
|
48
|
+
- **Passive Spam Block List** (PSBL)
|
|
49
|
+
- **InterServer RBL**
|
|
50
|
+
- **Spamhaus SBL**
|
|
51
|
+
- **all.s5h.net**
|
|
52
|
+
- **Abuse.ch Combined**
|
|
53
|
+
- **UCEPROTECT Level 2**
|
|
54
|
+
- **Abuse.ch Drone**
|
|
55
|
+
- **OrveDB AuBads**
|
|
56
|
+
- **0spam RBL**
|
|
57
|
+
- **Singular TTK PTE**
|
|
58
|
+
- **SpamRats Spam**
|
|
59
|
+
- **Spamsources Fabel**
|
|
60
|
+
- **Virus RBL JP**
|
|
61
|
+
- **Woody's SMTP Blacklist**
|
|
62
|
+
- **WPBL**
|
|
63
|
+
- **UCEPROTECT Level 3**
|
|
64
|
+
- **Duinv AuPads**
|
|
65
|
+
- **Gweep Proxy**
|
|
66
|
+
- **Gweep Relays**
|
|
67
|
+
- **Abuse.ch Spam**
|
|
68
|
+
- **Digibase Spambot**
|
|
69
|
+
- **Lashback UBL**
|
|
70
|
+
- **WormRBL**
|
|
71
|
+
- **0spam Blocklist**
|
|
72
|
+
- **Team Cymru Bogons**
|
|
73
|
+
- **SpamRats Dyna**
|
|
74
|
+
- **SpamRats NoPtr**
|
|
75
|
+
- **Nether.net Relays**
|
|
76
|
+
- **Imp.ch Spam RBL**
|
|
77
|
+
- **Mailspike Z**
|
|
78
|
+
- **Anonmails.de**
|
|
79
|
+
- **Pedantic.org**
|
|
80
|
+
- **Swinog**
|
|
81
|
+
- **GBUdb Truncate**
|
|
82
|
+
- **LashBack UBL**
|
|
83
|
+
|
|
84
|
+
## How to use it
|
|
85
|
+
|
|
86
|
+
### 1. Install
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npm install uptimeify-dnsbl
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 2. Check an IP
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
import { getLookupDomains, parseLookupResult } from "uptimeify-dnsbl";
|
|
96
|
+
import { resolve4 } from "node:dns/promises";
|
|
97
|
+
|
|
98
|
+
async function check(ip) {
|
|
99
|
+
// 1. Get the list of domains to query
|
|
100
|
+
const checks = getLookupDomains(ip);
|
|
101
|
+
// Returns array: [{ address: "4.3.2.1.zen.spamhaus.org", listKey: "zen.spamhaus.org" }, ...]
|
|
102
|
+
|
|
103
|
+
// 2. Run your DNS lookups
|
|
104
|
+
// We use typical Promise handling here, but you can use any async pattern
|
|
105
|
+
const results = await Promise.allSettled(
|
|
106
|
+
checks.map(async ({ address, listKey }) => {
|
|
107
|
+
// A successful DNS A-record lookup means the IP is listed.
|
|
108
|
+
// If the IP is clean, resolve4 throws ENOTFOUND.
|
|
109
|
+
const [code] = await resolve4(address);
|
|
110
|
+
return parseLookupResult(listKey, code);
|
|
111
|
+
}),
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// 3. Process results
|
|
115
|
+
const listings = results
|
|
116
|
+
.filter((r) => r.status === "fulfilled") // Successful lookup = Listed
|
|
117
|
+
.map((r) => r.value);
|
|
118
|
+
|
|
119
|
+
if (listings.length > 0) {
|
|
120
|
+
console.log(`❌ IP ${ip} is listed on:`);
|
|
121
|
+
listings.forEach((listing) => {
|
|
122
|
+
console.log(` - ${listing.name}`);
|
|
123
|
+
console.log(` Reason: ${listing.reason}`);
|
|
124
|
+
console.log(` Delist: ${listing.delistUrl}`);
|
|
125
|
+
});
|
|
126
|
+
} else {
|
|
127
|
+
console.log(`✅ IP ${ip} is clean.`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
check("127.0.0.2");
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## API
|
|
135
|
+
|
|
136
|
+
### `getLookupDomains(ip)`
|
|
137
|
+
|
|
138
|
+
Returns an array of objects containing the fully qualified domain to query (`address`) and the identifier key (`listKey`).
|
|
139
|
+
|
|
140
|
+
### `parseLookupResult(listKey, resultCode)`
|
|
141
|
+
|
|
142
|
+
Takes the list identifier and the IP address returned by the DNS query (e.g., `127.0.0.2`) and returns a rich object with the listing name, reason, and delist URL.
|
|
143
|
+
|
|
144
|
+
### `parseLookupResultJson(listKey, resultCode)`
|
|
145
|
+
|
|
146
|
+
Same as `parseLookupResult`, but returns a stringified JSON representation of the result.
|
package/examples/test.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Uptimeify DNSBL - Usage Example
|
|
3
|
+
*
|
|
4
|
+
* This script demonstrates how to identify if an IP address is blacklisted
|
|
5
|
+
* using the helper functions provided by this library.
|
|
6
|
+
*
|
|
7
|
+
* Workflow:
|
|
8
|
+
* 1. Generate lookup domains using `getLookupDomains(ip)`
|
|
9
|
+
* 2. Query these domains using standard DNS lookups (A records)
|
|
10
|
+
* 3. Parse the results using `parseLookupResult(listKey, code)`
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
getLookupDomains,
|
|
15
|
+
parseLookupResult,
|
|
16
|
+
parseLookupResultJson,
|
|
17
|
+
} from "../src/index.js";
|
|
18
|
+
import { resolve4 } from "node:dns/promises";
|
|
19
|
+
import { performance } from "node:perf_hooks";
|
|
20
|
+
|
|
21
|
+
async function checkIP(ip) {
|
|
22
|
+
console.log(`\n🔎 Checking IP: ${ip}`);
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// 1. Get the list of all DNSBL domains to query for this IP
|
|
26
|
+
const startGetDomains = performance.now();
|
|
27
|
+
const domains = getLookupDomains(ip);
|
|
28
|
+
const endGetDomains = performance.now();
|
|
29
|
+
console.log(
|
|
30
|
+
` Preparing to query ${domains.length} blacklists... (took ${(endGetDomains - startGetDomains).toFixed(5)}ms)`,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
let totalParseTime = 0;
|
|
34
|
+
|
|
35
|
+
// 2. Perform DNS lookups in parallel
|
|
36
|
+
// Note: handling DNS queries is outside the scope of the library,
|
|
37
|
+
// but standard Node.js 'dns' module works perfectly.
|
|
38
|
+
const results = await Promise.all(
|
|
39
|
+
domains.map(async ({ address, listKey }) => {
|
|
40
|
+
try {
|
|
41
|
+
// resolve4 throws ENOTFOUND if the record doesn't exist (IP is clean)
|
|
42
|
+
const addresses = await resolve4(address);
|
|
43
|
+
const code = addresses[0]; // e.g., '127.0.0.2'
|
|
44
|
+
|
|
45
|
+
// 3. Parse the returned code into a readable structure
|
|
46
|
+
const startParse = performance.now();
|
|
47
|
+
const result = parseLookupResult(listKey, code);
|
|
48
|
+
const endParse = performance.now();
|
|
49
|
+
totalParseTime += endParse - startParse;
|
|
50
|
+
|
|
51
|
+
return result;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (error.code === "ENOTFOUND") {
|
|
54
|
+
// Domain not found = IP is not on this blacklist
|
|
55
|
+
return {
|
|
56
|
+
name: listKey,
|
|
57
|
+
listed: false,
|
|
58
|
+
reason: "Not Listed",
|
|
59
|
+
code: null,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// Handle other DNS errors
|
|
63
|
+
return {
|
|
64
|
+
name: listKey,
|
|
65
|
+
listed: false,
|
|
66
|
+
reason: `DNS Error: ${error.code}`,
|
|
67
|
+
code: null,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
console.log(
|
|
74
|
+
` [Perf] Cumulative time in parseLookupResult: ${totalParseTime.toFixed(5)}ms`,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
// Display the findings
|
|
78
|
+
const listed = results.filter((r) => r.listed);
|
|
79
|
+
|
|
80
|
+
if (listed.length > 0) {
|
|
81
|
+
console.log(`\n❌ [LISTED] Found in ${listed.length} blacklists:`);
|
|
82
|
+
listed.forEach((res) => {
|
|
83
|
+
console.log(` - ${res.name}`);
|
|
84
|
+
console.log(` Reason: ${res.reason}`);
|
|
85
|
+
console.log(` Code: ${res.code}`);
|
|
86
|
+
if (res.delistUrl) {
|
|
87
|
+
console.log(` Delist: ${res.delistUrl}`);
|
|
88
|
+
}
|
|
89
|
+
console.log("");
|
|
90
|
+
});
|
|
91
|
+
} else {
|
|
92
|
+
console.log("✅ [CLEAN] IP is not listed in any supported blacklists.");
|
|
93
|
+
}
|
|
94
|
+
} catch (err) {
|
|
95
|
+
console.error("Critical Error during check:", err.message);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// --- Execution ---
|
|
100
|
+
|
|
101
|
+
console.log("--- DNSBL Verification Utility ---");
|
|
102
|
+
|
|
103
|
+
// Check IPv4
|
|
104
|
+
await checkIP("213.209.159.159");
|
|
105
|
+
|
|
106
|
+
// Check IPv6
|
|
107
|
+
await checkIP("2a06:4880:8000::99");
|
|
108
|
+
|
|
109
|
+
// Check JSON Parsing Feature
|
|
110
|
+
console.log("\n-----------------------------------");
|
|
111
|
+
console.log("ℹ️ JSON Output Test:");
|
|
112
|
+
const startJson = performance.now();
|
|
113
|
+
const demoJson = parseLookupResultJson("zen.spamhaus.org", "127.0.0.4");
|
|
114
|
+
const endJson = performance.now();
|
|
115
|
+
console.log(demoJson);
|
|
116
|
+
console.log(` (took ${(endJson - startJson).toFixed(5)}ms)`);
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "uptimeify-dnsbl",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Helper module to prepare DNSBL queries and parse results.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./src/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "node examples/test.js"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"dnsbl",
|
|
16
|
+
"blacklist",
|
|
17
|
+
"spam",
|
|
18
|
+
"check"
|
|
19
|
+
],
|
|
20
|
+
"author": "Uptimeify",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=20.0.0 <25.0.0"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} BlacklistDefinition
|
|
3
|
+
* @property {string} name - The human-readable name of the blacklist
|
|
4
|
+
* @property {string} delistUrl - URL where a user can request removal
|
|
5
|
+
* @property {Object.<string, string>} mappings - Mapping of return codes (IPs) to reasons
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Definition of known blacklists and their return codes.
|
|
10
|
+
* @type {Object.<string, BlacklistDefinition>}
|
|
11
|
+
*/
|
|
12
|
+
export const blacklists = {
|
|
13
|
+
"zen.spamhaus.org": {
|
|
14
|
+
name: "Spamhaus ZEN",
|
|
15
|
+
delistUrl: "https://check.spamhaus.org/",
|
|
16
|
+
mappings: {
|
|
17
|
+
"127.0.0.2": "Listed in SBL (Spamhaus Block List - Direct spam sources)",
|
|
18
|
+
"127.0.0.3":
|
|
19
|
+
"Listed in CSS (Combating Spam Syndicate - Compromised hosts)",
|
|
20
|
+
"127.0.0.4":
|
|
21
|
+
"Listed in XBL/PBL (Exploits/Policy Block List - Botnets, open proxies, dynamic IPs)",
|
|
22
|
+
"127.0.0.5":
|
|
23
|
+
"Listed in XBL/PBL (Exploits/Policy Block List - Botnets, open proxies, dynamic IPs)",
|
|
24
|
+
"127.0.0.6":
|
|
25
|
+
"Listed in XBL/PBL (Exploits/Policy Block List - Botnets, open proxies, dynamic IPs)",
|
|
26
|
+
"127.0.0.7":
|
|
27
|
+
"Listed in XBL/PBL (Exploits/Policy Block List - Botnets, open proxies, dynamic IPs)",
|
|
28
|
+
"127.0.0.10": "PBL - ISP Policy",
|
|
29
|
+
"127.0.0.11": "PBL - ISP Policy",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
"b.barracudacentral.org": {
|
|
33
|
+
name: "Barracuda Reputation Block List",
|
|
34
|
+
delistUrl: "https://www.barracudacentral.org/rbl/removal-request",
|
|
35
|
+
mappings: {
|
|
36
|
+
"127.0.0.2": "Listed in Barracuda RBL",
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
"bl.spamcop.net": {
|
|
40
|
+
name: "SpamCop Blocking List",
|
|
41
|
+
delistUrl: "https://www.spamcop.net/bl.shtml",
|
|
42
|
+
mappings: {
|
|
43
|
+
"127.0.0.2": "Listed in SpamCop",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
"combined.mail.abusix.zone": {
|
|
47
|
+
name: "Abusix Mail Intelligence",
|
|
48
|
+
delistUrl: "https://abusix.com/lookup/",
|
|
49
|
+
mappings: {
|
|
50
|
+
"127.0.0.2": "Blacklisted (Generic)",
|
|
51
|
+
"127.0.0.3": "Blacklisted (External)",
|
|
52
|
+
"127.0.0.4": "Blacklisted (Dynamic/Policy)",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
"dnsbl.sorbs.net": {
|
|
56
|
+
name: "SORBS Aggregate",
|
|
57
|
+
delistUrl: "http://www.sorbs.net/lookup.shtml",
|
|
58
|
+
mappings: {
|
|
59
|
+
"127.0.0.2": "HTTP Proxy",
|
|
60
|
+
"127.0.0.3": "SOCKS Proxy",
|
|
61
|
+
"127.0.0.4": "Misc Proxy",
|
|
62
|
+
"127.0.0.5": "SMTP Relay",
|
|
63
|
+
"127.0.0.6": "Spam Source",
|
|
64
|
+
"127.0.0.7": "Web Spam",
|
|
65
|
+
"127.0.0.8": "Block List",
|
|
66
|
+
"127.0.0.9": "Zombie",
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
"dnsbl-1.uceprotect.net": {
|
|
70
|
+
name: "UCEPROTECT Level 1",
|
|
71
|
+
delistUrl: "http://www.uceprotect.net/en/rblcheck.php",
|
|
72
|
+
mappings: {
|
|
73
|
+
"127.0.0.2": "Listed in UCEPROTECT Level 1",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
"nodes.junkemailfilter.com": {
|
|
77
|
+
name: "Hostkarma",
|
|
78
|
+
delistUrl: "http://www.junkemailfilter.com/",
|
|
79
|
+
mappings: {
|
|
80
|
+
"127.0.0.2": "Blacklisted (Spam Source)",
|
|
81
|
+
"127.0.0.3": "Yellow list (Mixed spam/non-spam)",
|
|
82
|
+
"127.0.0.4": "Brown list (Suspicious/Score)",
|
|
83
|
+
"127.0.0.5": "No Blacklist (Do not block)",
|
|
84
|
+
"127.0.0.1": "Whitelisted (Pass)",
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
"ips.backscatterer.org": {
|
|
88
|
+
name: "Backscatterer",
|
|
89
|
+
delistUrl: "http://www.backscatterer.org/?target=test",
|
|
90
|
+
mappings: {
|
|
91
|
+
"127.0.0.2": "Listed in Backscatterer",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
"ivm-sip.invaluement.com": {
|
|
95
|
+
name: "Invaluement SIP",
|
|
96
|
+
delistUrl: "https://www.invaluement.com/lookup/",
|
|
97
|
+
mappings: {
|
|
98
|
+
"127.0.0.2": "Listed in Invaluement SIP",
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
"bl.spamcannibal.org": {
|
|
102
|
+
name: "SpamCannibal",
|
|
103
|
+
delistUrl: "http://www.spamcannibal.org/",
|
|
104
|
+
mappings: {
|
|
105
|
+
"127.0.0.2": "Listed in SpamCannibal",
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
"dnsbl.dronebl.org": {
|
|
109
|
+
name: "DroneBL",
|
|
110
|
+
delistUrl: "https://dronebl.org/lookup",
|
|
111
|
+
mappings: {
|
|
112
|
+
"127.0.0.2": "Sample",
|
|
113
|
+
"127.0.0.3": "IRC Drone",
|
|
114
|
+
"127.0.0.5": "Bottler",
|
|
115
|
+
"127.0.0.6": "Glass bot",
|
|
116
|
+
"127.0.0.7": "DDoS Drone",
|
|
117
|
+
"127.0.0.8": "SOCKS Proxy",
|
|
118
|
+
"127.0.0.9": "HTTP Proxy",
|
|
119
|
+
"127.0.0.10": "ProxyChain",
|
|
120
|
+
"127.0.0.11": "Web Page Proxy",
|
|
121
|
+
"127.0.0.12": "Open DNS Resolver",
|
|
122
|
+
"127.0.0.13": "Brute Force Attackers",
|
|
123
|
+
"127.0.0.14": "Open Wingate Proxy",
|
|
124
|
+
"127.0.0.15": "Compromised Router / Gateway",
|
|
125
|
+
"127.0.0.16": "Rootkit / Trojan",
|
|
126
|
+
"127.0.0.17": "Automatically Determined Botnet (Tracker)",
|
|
127
|
+
"127.0.0.18": "DNSBL / Tor Exit Node",
|
|
128
|
+
"127.0.0.255": "Unknown",
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
"bl.spameatingmonkey.net": {
|
|
132
|
+
name: "Spam Eating Monkey SEM-BLACK",
|
|
133
|
+
delistUrl: "https://spameatingmonkey.com/lookup",
|
|
134
|
+
mappings: {
|
|
135
|
+
"127.0.0.2": "Listed in SEM-BLACK",
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
"black.uribl.com": {
|
|
139
|
+
name: "URIBL Black",
|
|
140
|
+
delistUrl: "https://lookup.uribl.com/",
|
|
141
|
+
mappings: {
|
|
142
|
+
"127.0.0.2": "Listed in URIBL Black",
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
"dnsbl.madavi.de": {
|
|
146
|
+
name: "Madavi DNSBL",
|
|
147
|
+
delistUrl: "https://www.madavi.de/en/dnsbl.html",
|
|
148
|
+
mappings: {
|
|
149
|
+
"127.0.0.2": "Listed in Madavi DNSBL",
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
"dnsbl.rv-soft.info": {
|
|
153
|
+
name: "RV-SOFT Technology DNSBL",
|
|
154
|
+
delistUrl: "http://dnsbl.rv-soft.info",
|
|
155
|
+
mappings: {
|
|
156
|
+
"127.0.0.2": "Open relay",
|
|
157
|
+
"127.0.0.3": "Open proxy",
|
|
158
|
+
"127.0.0.4": "Spam source",
|
|
159
|
+
"127.0.0.5": "Malware domain",
|
|
160
|
+
"127.0.0.6": "Phishing messages",
|
|
161
|
+
"127.0.0.7": "Spear phishing messages",
|
|
162
|
+
"127.0.0.8": "Fraudulent messages, HOAX",
|
|
163
|
+
"127.0.0.9": "Blackmail messages",
|
|
164
|
+
"127.0.0.10": "Spam from End User, local PC",
|
|
165
|
+
"127.0.0.11": "Non-RFC Compliant",
|
|
166
|
+
"127.0.0.12": "Does not properly handle 5xx errors",
|
|
167
|
+
"127.0.0.13": "Compromised System - DDoS",
|
|
168
|
+
"127.0.0.14": "Compromised System - Relay",
|
|
169
|
+
"127.0.0.15": "Compromised System - Proxy",
|
|
170
|
+
"127.0.0.16": "Compromised System - Autorooter/Scanner",
|
|
171
|
+
"127.0.0.17": "Compromised System - Mass mailing virus",
|
|
172
|
+
"127.0.0.18": "Compromised System - Mass mailing phishing",
|
|
173
|
+
"127.0.0.19": "Bad reputation",
|
|
174
|
+
"127.0.0.20": "Mass distribution",
|
|
175
|
+
"127.0.0.126": "Other reason",
|
|
176
|
+
"127.0.0.127": "Private record",
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
"dnsbl.zapbl.net": {
|
|
180
|
+
name: "ZapBL",
|
|
181
|
+
delistUrl: "http://zapbl.net/",
|
|
182
|
+
mappings: {
|
|
183
|
+
"127.0.0.2": "Listed in ZapBL",
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
"gl.suomispam.net": {
|
|
187
|
+
name: "Suomispam Reputation",
|
|
188
|
+
delistUrl: "https://suomispam.net/",
|
|
189
|
+
mappings: {
|
|
190
|
+
"127.0.0.2": "Listed in Suomispam",
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
"dnsbl.kempt.net": {
|
|
194
|
+
name: "Kempt.net DNSBL",
|
|
195
|
+
delistUrl: "http://dnsbl.kempt.net/",
|
|
196
|
+
mappings: {
|
|
197
|
+
"127.0.0.2": "Listed in Kempt.net",
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
"korea.services.net": {
|
|
201
|
+
name: "Korea Services DNSBL",
|
|
202
|
+
delistUrl: "http://www.korea.services.net/",
|
|
203
|
+
mappings: {
|
|
204
|
+
"127.0.0.2": "Listed in Korea Services",
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
"nixspam.heise.de": {
|
|
208
|
+
name: "NiX Spam",
|
|
209
|
+
delistUrl: "https://www.heise.de/ix/nixspam/",
|
|
210
|
+
mappings: {
|
|
211
|
+
"127.0.0.2": "Listed in NiX Spam",
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
"psbl.surriel.com": {
|
|
215
|
+
name: "Passive Spam Block List (PSBL)",
|
|
216
|
+
delistUrl: "http://psbl.surriel.com/",
|
|
217
|
+
mappings: {
|
|
218
|
+
"127.0.0.2": "Listed in PSBL",
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
"rbl.interserver.net": {
|
|
222
|
+
name: "InterServer RBL",
|
|
223
|
+
delistUrl: "http://rbl.interserver.net/",
|
|
224
|
+
mappings: {
|
|
225
|
+
"127.0.0.2": "Listed in InterServer RBL",
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
"sbl.spamhaus.org": {
|
|
229
|
+
name: "Spamhaus SBL",
|
|
230
|
+
delistUrl: "https://check.spamhaus.org/",
|
|
231
|
+
mappings: {
|
|
232
|
+
"127.0.0.2": "Listed in SBL (Spamhaus Block List)",
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
"spam.dnsbl.anonmails.de": {
|
|
236
|
+
name: "Anonmails.de DNSBL",
|
|
237
|
+
delistUrl: "https://spam.dnsbl.anonmails.de/",
|
|
238
|
+
mappings: {
|
|
239
|
+
"127.0.0.2": "Listed in Anonmails.de",
|
|
240
|
+
},
|
|
241
|
+
},
|
|
242
|
+
"spam.pedantic.org": {
|
|
243
|
+
name: "Pedantic.org spam list",
|
|
244
|
+
delistUrl: "http://www.pedantic.org/",
|
|
245
|
+
mappings: {
|
|
246
|
+
"127.0.0.2": "Listed in Pedantic.org",
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
"swinog.spam.dnsbl.ch": {
|
|
250
|
+
name: "Swinog DNSBL",
|
|
251
|
+
delistUrl: "https://www.swinog.ch/spam/",
|
|
252
|
+
mappings: {
|
|
253
|
+
"127.0.0.2": "Listed in Swinog",
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
"truncate.gbudb.net": {
|
|
257
|
+
name: "GBUdb Truncate",
|
|
258
|
+
delistUrl: "http://www.gbudb.com/truncate/",
|
|
259
|
+
mappings: {
|
|
260
|
+
"127.0.0.2": "Listed in GBUdb",
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
"ubl.unsubscore.com": {
|
|
264
|
+
name: "LashBack UBL",
|
|
265
|
+
delistUrl: "https://blacklist.lashback.com/",
|
|
266
|
+
mappings: {
|
|
267
|
+
"127.0.0.2": "Listed in LashBack UBL",
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
"all.s5h.net": {
|
|
271
|
+
name: "all.s5h.net",
|
|
272
|
+
delistUrl: "http://s5h.net",
|
|
273
|
+
mappings: {
|
|
274
|
+
"127.0.0.2": "Listed in all.s5h.net",
|
|
275
|
+
},
|
|
276
|
+
},
|
|
277
|
+
"combined.abuse.ch": {
|
|
278
|
+
name: "Abuse.ch Combined",
|
|
279
|
+
delistUrl: "https://abuse.ch",
|
|
280
|
+
mappings: {
|
|
281
|
+
"127.0.0.2": "Listed in Abuse.ch",
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
"dnsbl-2.uceprotect.net": {
|
|
285
|
+
name: "UCEPROTECT Level 2",
|
|
286
|
+
delistUrl: "http://www.uceprotect.net/en/rblcheck.php",
|
|
287
|
+
mappings: {
|
|
288
|
+
"127.0.0.2": "Listed in UCEPROTECT Level 2",
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
"drone.abuse.ch": {
|
|
292
|
+
name: "Abuse.ch Drone",
|
|
293
|
+
delistUrl: "https://abuse.ch",
|
|
294
|
+
mappings: {
|
|
295
|
+
"127.0.0.2": "Listed in Abuse.ch Drone",
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
"orvedb.aupads.org": {
|
|
299
|
+
name: "OrveDB AuBads",
|
|
300
|
+
delistUrl: "https://aupads.org",
|
|
301
|
+
mappings: {
|
|
302
|
+
"127.0.0.2": "Listed in OrveDB",
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
"rbl.0spam.org": {
|
|
306
|
+
name: "0spam RBL",
|
|
307
|
+
delistUrl: "https://0spam.org",
|
|
308
|
+
mappings: {
|
|
309
|
+
"127.0.0.2": "Listed in 0spam RBL",
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
"singular.ttk.pte.hu": {
|
|
313
|
+
name: "Singular TTK PTE",
|
|
314
|
+
delistUrl: "http://singular.ttk.pte.hu",
|
|
315
|
+
mappings: {
|
|
316
|
+
"127.0.0.2": "Listed in Singular TTK PTE",
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
"spam.spamrats.com": {
|
|
320
|
+
name: "SpamRats Spam",
|
|
321
|
+
delistUrl: "https://www.spamrats.com",
|
|
322
|
+
mappings: {
|
|
323
|
+
"127.0.0.38": "Listed in SpamRats Spam",
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
"spamsources.fabel.dk": {
|
|
327
|
+
name: "Spamsources Fabel",
|
|
328
|
+
delistUrl: "http://www.fabel.dk",
|
|
329
|
+
mappings: {
|
|
330
|
+
"127.0.0.2": "Listed in Spamsources Fabel",
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
"virus.rbl.jp": {
|
|
334
|
+
name: "Virus RBL JP",
|
|
335
|
+
delistUrl: "http://www.rbl.jp",
|
|
336
|
+
mappings: {
|
|
337
|
+
"127.0.0.2": "Listed in Virus RBL JP",
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
"blacklist.woody.ch": {
|
|
341
|
+
name: "Woody's SMTP Blacklist",
|
|
342
|
+
delistUrl: "http://blacklist.woody.ch",
|
|
343
|
+
mappings: {
|
|
344
|
+
"127.0.0.2": "Listed in Woody's",
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
"db.wpbl.info": {
|
|
348
|
+
name: "WPBL",
|
|
349
|
+
delistUrl: "http://wpbl.info",
|
|
350
|
+
mappings: {
|
|
351
|
+
"127.0.0.2": "Listed in WPBL",
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
"dnsbl-3.uceprotect.net": {
|
|
355
|
+
name: "UCEPROTECT Level 3",
|
|
356
|
+
delistUrl: "http://www.uceprotect.net/en/rblcheck.php",
|
|
357
|
+
mappings: {
|
|
358
|
+
"127.0.0.2": "Listed in UCEPROTECT Level 3",
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
"duinv.aupads.org": {
|
|
362
|
+
name: "Duinv AuPads",
|
|
363
|
+
delistUrl: "https://aupads.org",
|
|
364
|
+
mappings: {
|
|
365
|
+
"127.0.0.2": "Listed in Duinv",
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
"proxy.bl.gweep.ca": {
|
|
369
|
+
name: "Gweep Proxy",
|
|
370
|
+
delistUrl: "http://gweep.ca",
|
|
371
|
+
mappings: {
|
|
372
|
+
"127.0.0.2": "Listed in Gweep Proxy",
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
"relays.bl.gweep.ca": {
|
|
376
|
+
name: "Gweep Relays",
|
|
377
|
+
delistUrl: "http://gweep.ca",
|
|
378
|
+
mappings: {
|
|
379
|
+
"127.0.0.2": "Listed in Gweep Relays",
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
"spam.abuse.ch": {
|
|
383
|
+
name: "Abuse.ch Spam",
|
|
384
|
+
delistUrl: "https://abuse.ch",
|
|
385
|
+
mappings: {
|
|
386
|
+
"127.0.0.2": "Listed in Abuse.ch Spam",
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
"spambot.bls.digibase.ca": {
|
|
390
|
+
name: "Digibase Spambot",
|
|
391
|
+
delistUrl: "http://bls.digibase.ca",
|
|
392
|
+
mappings: {
|
|
393
|
+
"127.0.0.2": "Listed in Digibase Spambot",
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
"ubl.lashback.com": {
|
|
397
|
+
name: "Lashback UBL",
|
|
398
|
+
delistUrl: "https://blacklist.lashback.com",
|
|
399
|
+
mappings: {
|
|
400
|
+
"127.0.0.2": "Listed in Lashback UBL",
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
"wormrbl.imp.ch": {
|
|
404
|
+
name: "WormRBL",
|
|
405
|
+
delistUrl: "http://antispam.imp.ch",
|
|
406
|
+
mappings: {
|
|
407
|
+
"127.0.0.2": "Listed in WormRBL",
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
"bl.0spam.org": {
|
|
411
|
+
name: "0spam Blocklist",
|
|
412
|
+
delistUrl: "https://0spam.org",
|
|
413
|
+
mappings: {
|
|
414
|
+
"127.0.0.2": "Listed in 0spam",
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
"bogons.cymru.com": {
|
|
418
|
+
name: "Team Cymru Bogons",
|
|
419
|
+
delistUrl: "https://www.team-cymru.com/bogon-reference.html",
|
|
420
|
+
mappings: {
|
|
421
|
+
"127.0.0.2": "Listed in Bogons",
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
"dyna.spamrats.com": {
|
|
425
|
+
name: "SpamRats Dyna",
|
|
426
|
+
delistUrl: "https://www.spamrats.com",
|
|
427
|
+
mappings: {
|
|
428
|
+
"127.0.0.36": "Listed in SpamRats Dyna",
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
"noptr.spamrats.com": {
|
|
432
|
+
name: "SpamRats NoPtr",
|
|
433
|
+
delistUrl: "https://www.spamrats.com",
|
|
434
|
+
mappings: {
|
|
435
|
+
"127.0.0.38": "Listed in SpamRats NoPtr",
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
"relays.nether.net": {
|
|
439
|
+
name: "Nether.net Relays",
|
|
440
|
+
delistUrl: "http://puck.nether.net/bl/",
|
|
441
|
+
mappings: {
|
|
442
|
+
"127.0.0.2": "Listed in Nether.net",
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
"spamrbl.imp.ch": {
|
|
446
|
+
name: "Imp.ch Spam RBL",
|
|
447
|
+
delistUrl: "http://antispam.imp.ch",
|
|
448
|
+
mappings: {
|
|
449
|
+
"127.0.0.2": "Listed in Imp.ch",
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
"z.mailspike.net": {
|
|
453
|
+
name: "Mailspike Z",
|
|
454
|
+
delistUrl: "http://mailspike.net",
|
|
455
|
+
mappings: {
|
|
456
|
+
"127.0.0.2": "Listed in Mailspike Z",
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
};
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export interface LookupDomain {
|
|
2
|
+
/** The domain to query (e.g. 2.0.0.127.zen.spamhaus.org) */
|
|
3
|
+
address: string;
|
|
4
|
+
/** The key of the blacklist (e.g. zen.spamhaus.org) */
|
|
5
|
+
listKey: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface LookupResult {
|
|
9
|
+
/** The name of the blacklist or listKey if unknown */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Whether the IP is listed (true) or not (false) */
|
|
12
|
+
listed: boolean;
|
|
13
|
+
/** The reason for listing or status message */
|
|
14
|
+
reason: string;
|
|
15
|
+
/** The IP returned by the DNS query, or null */
|
|
16
|
+
code: string | null;
|
|
17
|
+
/** URL to request delisting, or null */
|
|
18
|
+
delistUrl: string | null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface BlacklistDefinition {
|
|
22
|
+
/** The human-readable name of the blacklist */
|
|
23
|
+
name: string;
|
|
24
|
+
/** URL where a user can request removal */
|
|
25
|
+
delistUrl: string;
|
|
26
|
+
/** Mapping of return codes (IPs) to reasons */
|
|
27
|
+
mappings: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Definition of known blacklists and their return codes.
|
|
32
|
+
*/
|
|
33
|
+
export const blacklists: Record<string, BlacklistDefinition>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Generates the list of domains to query.
|
|
37
|
+
*
|
|
38
|
+
* @param ip - The IPv4 or IPv6 address to check.
|
|
39
|
+
* @returns List of domains to query.
|
|
40
|
+
*/
|
|
41
|
+
export function getLookupDomains(ip: string): LookupDomain[];
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Parses the result from a DNS A-record lookup.
|
|
45
|
+
*
|
|
46
|
+
* @param listKey - The blacklist domain (e.g. 'zen.spamhaus.org')
|
|
47
|
+
* @param resultCode - The IP returned by the DNS query (e.g. '127.0.0.2')
|
|
48
|
+
* @returns Human readable result
|
|
49
|
+
*/
|
|
50
|
+
export function parseLookupResult(
|
|
51
|
+
listKey: string,
|
|
52
|
+
resultCode: string,
|
|
53
|
+
): LookupResult;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Parses the result from a DNS A-record lookup and returns a JSON string.
|
|
57
|
+
*
|
|
58
|
+
* @param listKey - The blacklist domain (e.g. 'zen.spamhaus.org')
|
|
59
|
+
* @param resultCode - The IP returned by the DNS query (e.g. '127.0.0.2')
|
|
60
|
+
* @returns JSON formatted string
|
|
61
|
+
*/
|
|
62
|
+
export function parseLookupResultJson(
|
|
63
|
+
listKey: string,
|
|
64
|
+
resultCode: string,
|
|
65
|
+
): string;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { blacklists } from "./definitions.js";
|
|
2
|
+
import net from "node:net";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @typedef {Object} LookupDomain
|
|
6
|
+
* @property {string} address - The domain to query (e.g. 2.0.0.127.zen.spamhaus.org)
|
|
7
|
+
* @property {string} listKey - The key of the blacklist (e.g. zen.spamhaus.org)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @typedef {Object} LookupResult
|
|
12
|
+
* @property {string} name - The name of the blacklist or listKey if unknown
|
|
13
|
+
* @property {boolean} listed - Whether the IP is listed (true) or not (false)
|
|
14
|
+
* @property {string} reason - The reason for listing or status message
|
|
15
|
+
* @property {string|null} code - The IP returned by the DNS query, or null
|
|
16
|
+
* @property {string|null} delistUrl - URL to request delisting, or null
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Reverses an IP address for DNSBL queries.
|
|
21
|
+
* Supports IPv4 and IPv6.
|
|
22
|
+
* @param {string} ip
|
|
23
|
+
* @returns {string|null} Reversed IP (d.c.b.a for IPv4, nibbles for IPv6) or null if invalid
|
|
24
|
+
*/
|
|
25
|
+
function reverseIP(ip) {
|
|
26
|
+
if (typeof ip !== "string") {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (net.isIPv4(ip)) {
|
|
31
|
+
return ip.split(".").reverse().join(".");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (net.isIPv6(ip)) {
|
|
35
|
+
try {
|
|
36
|
+
// Expand ::
|
|
37
|
+
let expanded = ip;
|
|
38
|
+
if (ip.indexOf("::") !== -1) {
|
|
39
|
+
const parts = ip.split("::");
|
|
40
|
+
const left = parts[0].split(":").filter((p) => p);
|
|
41
|
+
const right = parts[1].split(":").filter((p) => p);
|
|
42
|
+
const missing = 8 - (left.length + right.length);
|
|
43
|
+
// Safety check for invalid IPv6 length
|
|
44
|
+
if (missing < 0) return null;
|
|
45
|
+
const middle = new Array(missing).fill("0000");
|
|
46
|
+
expanded = [...left, ...middle, ...right].join(":");
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Check for IPv4-mapped IPv6 addresses (contain dots), not supported for now
|
|
50
|
+
if (expanded.includes(".")) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const segments = expanded.split(":").map((part) => part.padStart(4, "0"));
|
|
55
|
+
const fullHex = segments.join("");
|
|
56
|
+
|
|
57
|
+
return fullHex.split("").reverse().join(".");
|
|
58
|
+
} catch (e) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Generates the list of domains to query.
|
|
68
|
+
*
|
|
69
|
+
* @param {string} ip - The IPv4 or IPv6 address to check.
|
|
70
|
+
* @returns {Array<LookupDomain>} List of domains to query.
|
|
71
|
+
*/
|
|
72
|
+
export function getLookupDomains(ip) {
|
|
73
|
+
if (!ip || typeof ip !== "string") {
|
|
74
|
+
throw new Error("IP address must be a non-empty string");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const reversed = reverseIP(ip);
|
|
78
|
+
if (!reversed) {
|
|
79
|
+
throw new Error(`Invalid IP address: ${ip}`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return Object.keys(blacklists).map((listKey) => {
|
|
83
|
+
return {
|
|
84
|
+
address: `${reversed}.${listKey}`,
|
|
85
|
+
listKey: listKey,
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Parses the result from a DNS A-record lookup.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} listKey - The blacklist domain (e.g. 'zen.spamhaus.org')
|
|
94
|
+
* @param {string} resultCode - The IP returned by the DNS query (e.g. '127.0.0.2')
|
|
95
|
+
* @returns {LookupResult} Human readable result
|
|
96
|
+
*/
|
|
97
|
+
export function parseLookupResult(listKey, resultCode) {
|
|
98
|
+
if (!listKey || typeof listKey !== "string") {
|
|
99
|
+
return {
|
|
100
|
+
name: "Unknown",
|
|
101
|
+
listed: false,
|
|
102
|
+
reason: "Invalid list key provided",
|
|
103
|
+
code: resultCode || null,
|
|
104
|
+
delistUrl: null,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const hasProp = Object.prototype.hasOwnProperty.call(blacklists, listKey);
|
|
109
|
+
const listDef = hasProp ? blacklists[listKey] : null;
|
|
110
|
+
|
|
111
|
+
if (!listDef) {
|
|
112
|
+
return {
|
|
113
|
+
name: listKey,
|
|
114
|
+
listed: true,
|
|
115
|
+
reason: "Unknown List",
|
|
116
|
+
code: resultCode,
|
|
117
|
+
delistUrl: null,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
if (listKey === "nodes.junkemailfilter.com" && resultCode === "127.0.0.1") {
|
|
123
|
+
return {
|
|
124
|
+
name: listDef.name,
|
|
125
|
+
listed: false,
|
|
126
|
+
reason: listDef.mappings[resultCode] || "Whitelisted",
|
|
127
|
+
code: resultCode,
|
|
128
|
+
delistUrl: listDef.delistUrl,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const reason = listDef.mappings?.[resultCode] || "Listed (Unknown Reason)";
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
name: listDef.name,
|
|
136
|
+
listed: true,
|
|
137
|
+
reason: reason,
|
|
138
|
+
code: resultCode,
|
|
139
|
+
delistUrl: listDef.delistUrl,
|
|
140
|
+
};
|
|
141
|
+
} catch (error) {
|
|
142
|
+
return {
|
|
143
|
+
name: listDef.name || listKey,
|
|
144
|
+
listed: true,
|
|
145
|
+
reason: "Error parsing result",
|
|
146
|
+
code: resultCode,
|
|
147
|
+
delistUrl: listDef.delistUrl || null,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Parses the result from a DNS A-record lookup and returns a JSON string.
|
|
154
|
+
*
|
|
155
|
+
* @param {string} listKey - The blacklist domain (e.g. 'zen.spamhaus.org')
|
|
156
|
+
* @param {string} resultCode - The IP returned by the DNS query (e.g. '127.0.0.2')
|
|
157
|
+
* @returns {string} JSON formatted string
|
|
158
|
+
*/
|
|
159
|
+
export function parseLookupResultJson(listKey, resultCode) {
|
|
160
|
+
return JSON.stringify(parseLookupResult(listKey, resultCode));
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export { blacklists };
|