Update README.md
This commit is contained in:
parent
a6e17b06ed
commit
f1eccfbed5
5 changed files with 113 additions and 27 deletions
92
README.md
92
README.md
|
|
@ -1 +1,91 @@
|
|||
# Cloudflare WAF to AbuseIPDB
|
||||
# ☁️ Cloudflare WAF to AbuseIPDB
|
||||
This project is an automated script designed to fetch and report IP addresses that have triggered specific Cloudflare firewall events.
|
||||
It enables reporting incidents detected by Cloudflare WAF to AbuseIPDB.
|
||||
|
||||
|
||||
## 🛠️ Prerequisites
|
||||
- Node.js
|
||||
- npm (Node Package Manager)
|
||||
|
||||
|
||||
## 📃 Information
|
||||
If you want to make changes to the script from this repository, please kindly fork it first.
|
||||
|
||||
|
||||
## 🌌 Example Report
|
||||

|
||||
```
|
||||
IP 192.42.116.183 [T1] triggered Cloudflare WAF (firewallCustom).
|
||||
Action taken: CHALLENGE
|
||||
ASN: 1101 (IP-EEND-AS IP-EEND BV)
|
||||
HTTP protocol: HTTP/1.0 (method GET)
|
||||
Domain: blocklist.sefinek.net
|
||||
Endpoint: /
|
||||
Timestamp: 2024-08-17T00:15:53Z
|
||||
Ray ID: 8b4578e65f16b8e4
|
||||
Rule ID: cc5e7a6277d447eca9c1818934ba65c8
|
||||
User agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.66 Safari/537.36
|
||||
|
||||
Report generated by Node-Cloudflare-WAF-AbuseIPDB (https://github.com/sefinek24/Node-Cloudflare-WAF-AbuseIPDB)
|
||||
```
|
||||
|
||||
|
||||
## 📥 Installation
|
||||
1. Clone the repository.
|
||||
```bash
|
||||
git clone https://github.com/sefinek24/Node-Cloudflare-WAF-AbuseIPDB.git
|
||||
```
|
||||
2. Install dependencies.
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
3. Environment variables. Create a new `.env.default` file with the same content, then rename it to `.env`. Fill it with your tokens, etc. Remember to set `NODE_ENV` to `production`!
|
||||
4. Run the script.
|
||||
```bash
|
||||
node .
|
||||
```
|
||||
5. If you want to run the process 24/7, install the `PM2` module.
|
||||
```bash
|
||||
npm install pm2 -g
|
||||
```
|
||||
6. Modify the log paths in the `ecosystem.config.js` file to be correct and existing. You don't need to create `.log` files, just ensure the directory structure is accurate.
|
||||
7. Run the process continuously using `PM2` to ensure constant operation and automatic restart in case of a failure.
|
||||
```bash
|
||||
pm2 start
|
||||
```
|
||||
8. Save a snapshot of the currently running `Node.js` processes.
|
||||
```bash
|
||||
pm2 save
|
||||
```
|
||||
9. Add `PM2` to startup.
|
||||
```bash
|
||||
pm2 startup
|
||||
```
|
||||
10. Execute the command generated by PM2, e.g.:
|
||||
```bash
|
||||
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sefinek --hp /home/sefinek
|
||||
```
|
||||
11. That’s it! Monitor logs using the `pm2 logs` command.
|
||||
|
||||
|
||||
## 🔤 How to Get Tokens?
|
||||
### `CLOUDFLARE_ZONE_ID`
|
||||

|
||||
|
||||
### `CLOUDFLARE_API_KEY`
|
||||
1. Go to [dash.cloudflare.com/profile/api-tokens](https://dash.cloudflare.com/profile/api-tokens).
|
||||
2. Click the "Create Token" button.
|
||||
3. Select "Create Custom Token".
|
||||
4. 
|
||||
|
||||
### `ABUSEIPDB_API_KEY`
|
||||
Go to [www.abuseipdb.com/account/api](https://www.abuseipdb.com/account/api).
|
||||
|
||||
|
||||
## 💕 Credits
|
||||
This project is inspired by the [MHG-LAB/Cloudflare-WAF-to-AbuseIPDB](https://github.com/MHG-LAB/Cloudflare-WAF-to-AbuseIPDB) repository.
|
||||
I'm not particularly fond of Python and usually try to avoid using this programming language, which is why I decided to create this repository.
|
||||
|
||||
|
||||
## 📑 MIT License
|
||||
Copyright 2024 © by [Sefinek](https://sefinek.net). All Rights Reserved.
|
||||
BIN
images/brave_UY5737SsDdlS.png
Normal file
BIN
images/brave_UY5737SsDdlS.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
BIN
images/brave_lEvin0BcDcoK.png
Normal file
BIN
images/brave_lEvin0BcDcoK.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
images/brave_oWibgugvXlTH.png
Normal file
BIN
images/brave_oWibgugvXlTH.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
48
index.js
48
index.js
|
|
@ -1,5 +1,4 @@
|
|||
require('dotenv').config();
|
||||
|
||||
const axios = require('axios');
|
||||
const PAYLOAD = require('./scripts/payload.js');
|
||||
const generateComment = require('./scripts/generateComment.js');
|
||||
|
|
@ -12,31 +11,42 @@ const log = require('./scripts/log.js');
|
|||
const TIME_WINDOW_MS = 20 * 60 * 1000;
|
||||
const COOLDOWN_MS = 2000;
|
||||
const BLOCK_TIME_MS = 5 * 60 * 60 * 1000; // 5h
|
||||
const exceptedRuleIds = new Set(['fa01280809254f82978e827892db4e46']);
|
||||
|
||||
const fetchBlockedIPs = async () => {
|
||||
try {
|
||||
const response = await axios.post('https://api.cloudflare.com/client/v4/graphql', PAYLOAD, { headers: headers.CLOUDFLARE });
|
||||
if (!response.data?.data) {
|
||||
log('error', `Failed to retrieve data from Cloudflare (status ${response.status}). Missing permissions? Check your token. The required permission is Zone.Analytics.Read.`);
|
||||
return null;
|
||||
if (response.data?.data) {
|
||||
const events = response.data.data.viewer.zones[0].firewallEventsAdaptive;
|
||||
log('info', `Fetched ${events.length} events from Cloudflare`);
|
||||
return events;
|
||||
} else {
|
||||
throw new Error(`Failed to retrieve data from Cloudflare (status ${response.status}). Missing permissions? Check your token. The required permission is Zone.Analytics.Read.`);
|
||||
}
|
||||
|
||||
log('info', `Fetched ${response.data.data.viewer.zones[0].firewallEventsAdaptive.length} events from Cloudflare`);
|
||||
return response.data.data.viewer.zones[0].firewallEventsAdaptive;
|
||||
} catch (err) {
|
||||
if (err.response) {
|
||||
log('error', `${err.response.status} HTTP ERROR (api.cloudflare.com)\n${JSON.stringify(err.response.data, null, 2)}`);
|
||||
log('error', `${err.response.status} HTTP ERROR (Cloudflare)\n${JSON.stringify(err.response.data, null, 2)}`);
|
||||
} else if (err.request) {
|
||||
log('error', 'No response received from Cloudflare');
|
||||
} else {
|
||||
log('error', `Unknown error with api.cloudflare.com. ${err.message}`);
|
||||
log('error', `Unknown error with Cloudflare. ${err.message}`);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const reportIP = async (event, url, country, skippedRayIds, blockedIPs, cycleErrorCounts) => {
|
||||
const shouldReportDomain = (domain, reportedIPs) => {
|
||||
const lastReport = reportedIPs.find(entry => entry.domain === domain);
|
||||
return !lastReport || (Date.now() - lastReport.timestamp.getTime()) > TIME_WINDOW_MS;
|
||||
};
|
||||
|
||||
const isIPBlockedRecently = (ip, blockedIPs) => {
|
||||
const lastBlockTime = blockedIPs.get(ip);
|
||||
return lastBlockTime && (Date.now() - lastBlockTime) < BLOCK_TIME_MS;
|
||||
};
|
||||
|
||||
const reportIP = async (event, url, country, blockedIPs, cycleErrorCounts) => {
|
||||
try {
|
||||
await axios.post('https://api.abuseipdb.com/api/v2/report', {
|
||||
ip: event.clientIP,
|
||||
|
|
@ -51,7 +61,7 @@ const reportIP = async (event, url, country, skippedRayIds, blockedIPs, cycleErr
|
|||
if (err.response) {
|
||||
if (err.response.status === 429) {
|
||||
blockedIPs.set(event.clientIP, Date.now());
|
||||
logToCSV(new Date(), event.rayName, event.clientIP, url, 'Blocked - 429 Too Many Requests', country);
|
||||
logToCSV(new Date(), event.rayName, event.clientIP, url, 'Blocked - 429 Too Many Requests', event.clientCountryName);
|
||||
log('warn', `Rate limited (429) while reporting: ${event.clientIP}; URL: ${url}; (Will retry after 5 hours)`);
|
||||
cycleErrorCounts.blocked++;
|
||||
} else {
|
||||
|
|
@ -70,19 +80,6 @@ const reportIP = async (event, url, country, skippedRayIds, blockedIPs, cycleErr
|
|||
}
|
||||
};
|
||||
|
||||
const exceptedRuleIds = new Set(['fa01280809254f82978e827892db4e46']);
|
||||
|
||||
const shouldReportDomain = (domain, reportedIPs) => {
|
||||
const lastReport = reportedIPs.find(entry => entry.domain === domain);
|
||||
if (!lastReport) return true;
|
||||
return (Date.now() - lastReport.timestamp.getTime()) > TIME_WINDOW_MS;
|
||||
};
|
||||
|
||||
const isIPBlockedRecently = (ip, blockedIPs) => {
|
||||
const lastBlockTime = blockedIPs.get(ip);
|
||||
return lastBlockTime && (Date.now() - lastBlockTime) < BLOCK_TIME_MS;
|
||||
};
|
||||
|
||||
(async () => {
|
||||
log('info', 'Starting IP reporting process...');
|
||||
|
||||
|
|
@ -118,7 +115,7 @@ const isIPBlockedRecently = (ip, blockedIPs) => {
|
|||
}
|
||||
|
||||
if (!exceptedRuleIds.has(event.ruleId) && shouldReportDomain(event.clientRequestHTTPHost, reportedIPs)) {
|
||||
const wasReported = await reportIP(event, url, country, skippedRayIds, blockedIPs, cycleErrorCounts);
|
||||
const wasReported = await reportIP(event, url, country, blockedIPs, cycleErrorCounts);
|
||||
if (wasReported) {
|
||||
cycleReportedCount++;
|
||||
await new Promise(resolve => setTimeout(resolve, COOLDOWN_MS));
|
||||
|
|
@ -132,7 +129,6 @@ const isIPBlockedRecently = (ip, blockedIPs) => {
|
|||
}
|
||||
}
|
||||
|
||||
// Podsumowanie cyklu
|
||||
log('info', 'Cycle Summary:');
|
||||
log('info', `- Total IPs processed: ${cycleProcessedCount}`);
|
||||
log('info', `- Reported IPs: ${cycleReportedCount}`);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue