-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathindex.ts
More file actions
94 lines (77 loc) · 3.9 KB
/
index.ts
File metadata and controls
94 lines (77 loc) · 3.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import pLimit from 'p-limit';
import { chmodSync, existsSync, mkdirSync } from 'fs';
import cidrTools from 'cidr-tools';
const notSoBadASNs: string[] = ["13335"]; // Cloudflare
const outputDir = "./files";
interface RipeStatResponse {
data: {
prefixes: {
v4: { originating: string[]; transiting: string[]; };
v6: { originating: string[]; transiting: string[]; };
};
};
}
async function fetchBadASNs(): Promise<string[]> {
console.log("Fetching bad ASN list...");
const url = "https://raw.githubusercontent.com/O-X-L/risk-db-lists/refs/heads/main/asn/kind_hosting.txt";
const response = await fetch(url);
if (!response.ok) throw new Error(`Failed to fetch bad ASN list: ${response.statusText}`);
const text = await response.text();
const asns = text.split(/\r\n|\r|\n/).filter(asn => asn && !notSoBadASNs.includes(asn));
console.log(`Found ${asns.length} bad ASNs to process.`);
return asns.map(asn => `AS${asn}`);
}
async function fetchASNData(asn: string): Promise<{ ipv4: string[], ipv6: string[] }> {
const url = `https://stat.ripe.net/data/ris-prefixes/data.json?list_prefixes=true&types=o&resource=${asn}`;
try {
const response = await fetch(url, { headers: { 'User-Agent': 'Bun/1.0' } });
if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
const data = await response.json() as RipeStatResponse;
return {
ipv4: [...(data.data.prefixes.v4.originating || [])],
ipv6: [...(data.data.prefixes.v6.originating || [])],
};
} catch (error) {
console.warn(`\nFailed to fetch data for ${asn}: ${(error as Error).message}. Retrying in 5s...`);
await new Promise(resolve => setTimeout(resolve, 5000));
return fetchASNData(asn);
}
}
async function main() {
try {
if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true });
const badASNs = await fetchBadASNs();
const ipv4Set = new Set<string>();
const ipv6Set = new Set<string>();
const limit = pLimit(10);
let completed = 0;
const tasks = badASNs.map(asn => limit(async () => {
const { ipv4, ipv6 } = await fetchASNData(asn);
ipv4.forEach(p => ipv4Set.add(p));
ipv6.forEach(p => ipv6Set.add(p));
completed++;
process.stdout.write(`\rProgress: ${Math.floor(completed * 100 / badASNs.length)}% (${completed}/${badASNs.length}) - Fetched ${asn}`);
}));
await Promise.all(tasks);
console.log("\n\n100% : Finished downloading IP prefixes.");
const initialIpv4 = Array.from(ipv4Set).filter(ip => ip !== "0.0.0.0/0");
const initialIpv6 = Array.from(ipv6Set).filter(ip => ip !== "::/0");
console.log(`\nCollected ${initialIpv4.length} unique IPv4 and ${initialIpv6.length} unique IPv6 prefixes.`);
console.log("Merging subnets...");
const mergedIpv4 = cidrTools.mergeCidr(initialIpv4);
const mergedIpv6 = cidrTools.mergeCidr(initialIpv6);
console.log(`IPv4 list optimized from ${initialIpv4.length} to ${mergedIpv4.length} subnets.`);
console.log(`IPv6 list optimized from ${initialIpv6.length} to ${mergedIpv6.length} subnets.`);
await Bun.write(`${outputDir}/ipv4.txt`, mergedIpv4.join("\n"));
console.log(`List of bad IPs saved to ${outputDir}/ipv4.txt`);
await Bun.write(`${outputDir}/ipv6.txt`, mergedIpv6.join("\n"));
console.log(`List of bad IPs saved to ${outputDir}/ipv6.txt`);
await Bun.write(`${outputDir}/combined.txt`, `${mergedIpv4.join("\n")}\n${mergedIpv6.join("\n")}`);
console.log(`List of bad IPs saved to ${outputDir}/combined.txt`);
console.log("\nScript finished successfully!");
} catch (error) {
console.error("\nAn unexpected error occurred:", error);
process.exit(1);
}
}
main();