1.2.1
This commit is contained in:
parent
b1aad0b9c8
commit
d02259dca1
10 changed files with 57 additions and 39 deletions
|
|
@ -15,7 +15,7 @@ CYCLE_INTERVAL=120
|
||||||
|
|
||||||
# The minimum time (in hours) that must pass after reporting an IP address before it can be reported again.
|
# The minimum time (in hours) that must pass after reporting an IP address before it can be reported again.
|
||||||
# The required time is >= 15 minutes, according to AbuseIPDB API limits.
|
# The required time is >= 15 minutes, according to AbuseIPDB API limits.
|
||||||
REPORTED_IP_COOLDOWN_MS=7
|
REPORTED_IP_COOLDOWN=7
|
||||||
|
|
||||||
# The maximum URI length that can be reported to AbuseIPDB.
|
# The maximum URI length that can be reported to AbuseIPDB.
|
||||||
# If Cloudflare returns a longer URI, the API request will fail.
|
# If Cloudflare returns a longer URI, the API request will fail.
|
||||||
|
|
@ -29,12 +29,12 @@ SUCCESS_COOLDOWN=80
|
||||||
IP_REFRESH_INTERVAL=80
|
IP_REFRESH_INTERVAL=80
|
||||||
|
|
||||||
############################### SEFINEK API ###############################
|
############################### SEFINEK API ###############################
|
||||||
# Secret key for api.sefinek.net
|
|
||||||
SEFINEK_API_SECRET=
|
|
||||||
|
|
||||||
# Report IP addresses to api.sefinek.net to support the development of the repository at https://github.com/sefinek/Malicious-IP-Addresses. SEFINEK_API_SECRET is required if true.
|
# Report IP addresses to api.sefinek.net to support the development of the repository at https://github.com/sefinek/Malicious-IP-Addresses. SEFINEK_API_SECRET is required if true.
|
||||||
REPORT_TO_SEFINEK_API=false
|
REPORT_TO_SEFINEK_API=false
|
||||||
|
|
||||||
|
# Secret key for api.sefinek.net
|
||||||
|
SEFINEK_API_SECRET=
|
||||||
|
|
||||||
# How often should the log (reported_ips.csv) be analyzed and sent to the Sefinek API? In hours.
|
# How often should the log (reported_ips.csv) be analyzed and sent to the Sefinek API? In hours.
|
||||||
SEFINEK_API_INTERVAL=1
|
SEFINEK_API_INTERVAL=1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,8 @@ Also, take a look at [sefinek/UFW-AbuseIPDB-Reporter](https://github.com/sefinek
|
||||||
> If you like this repository or find it useful, I would greatly appreciate it if you could give it a star ⭐. Thanks a lot!
|
> If you like this repository or find it useful, I would greatly appreciate it if you could give it a star ⭐. Thanks a lot!
|
||||||
|
|
||||||
## 🛠️ Prerequisites
|
## 🛠️ Prerequisites
|
||||||
- [Node.js](https://nodejs.org)
|
- [Node.js + npm](https://nodejs.org)
|
||||||
- [npm](https://www.npmjs.com) (Node Package Manager)
|
- [PM2](https://www.npmjs.com/package/pm2) (recommended)
|
||||||
- [PM2](https://www.npmjs.com/package/pm2) (optional)
|
|
||||||
|
|
||||||
|
|
||||||
## 📃 Information
|
## 📃 Information
|
||||||
|
|
|
||||||
32
index.js
32
index.js
|
|
@ -1,7 +1,7 @@
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
|
|
||||||
const { axios, moduleVersion } = require('./services/axios.js');
|
const { axios, moduleVersion } = require('./services/axios.js');
|
||||||
const { CYCLE_INTERVAL, REPORTED_IP_COOLDOWN_MS, MAX_URL_LENGTH, SUCCESS_COOLDOWN, SEFINEK_API_INTERVAL, REPORT_TO_SEFINEK_API } = require('./scripts/config.js');
|
const { CYCLE_INTERVAL, REPORTED_IP_COOLDOWN, MAX_URL_LENGTH, SUCCESS_COOLDOWN, SEFINEK_API_INTERVAL, REPORT_TO_SEFINEK_API } = require('./scripts/config.js');
|
||||||
const PAYLOAD = require('./services/payload.js');
|
const PAYLOAD = require('./services/payload.js');
|
||||||
const generateComment = require('./scripts/generateComment.js');
|
const generateComment = require('./scripts/generateComment.js');
|
||||||
const SefinekAPI = require('./services/sefinekAPI.js');
|
const SefinekAPI = require('./services/sefinekAPI.js');
|
||||||
|
|
@ -20,9 +20,15 @@ const fetchBlockedIPs = async () => {
|
||||||
if (events) {
|
if (events) {
|
||||||
const filtered = events.filter(x =>
|
const filtered = events.filter(x =>
|
||||||
x.ip !== clientIp.getAddress() &&
|
x.ip !== clientIp.getAddress() &&
|
||||||
!whitelist.subdomains.some(subdomain => x.clientRequestHTTPHost?.includes(subdomain)) && // Subdomains
|
(
|
||||||
!whitelist.userAgents.some(ua => x.userAgent?.includes(ua)) && // User-agents
|
x.source === 'securitylevel' ||
|
||||||
!whitelist.endpoints.some(endpoint => x.clientRequestPath?.includes(endpoint)) // Endpoints
|
x.source === 'badscore' ||
|
||||||
|
(
|
||||||
|
!whitelist.domains.some(subdomain => x.clientRequestHTTPHost?.includes(subdomain)) &&
|
||||||
|
!whitelist.userAgents.some(ua => x.userAgent?.includes(ua)) &&
|
||||||
|
!whitelist.endpoints.some(endpoint => x.clientRequestPath?.includes(endpoint))
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
log('log', `Fetched ${events.length} (filtered ${filtered.length}) events from Cloudflare`);
|
log('log', `Fetched ${events.length} (filtered ${filtered.length}) events from Cloudflare`);
|
||||||
|
|
@ -46,7 +52,7 @@ const isIPReportedRecently = (rayId, ip, reportedIPs) => {
|
||||||
return latest;
|
return latest;
|
||||||
}, null);
|
}, null);
|
||||||
|
|
||||||
if (lastReport && (Date.now() - lastReport.timestamp) < REPORTED_IP_COOLDOWN_MS) {
|
if (lastReport && (Date.now() - lastReport.timestamp) < REPORTED_IP_COOLDOWN) {
|
||||||
return { recentlyReported: true, timeDifference: Date.now() - lastReport.timestamp, reason: lastReport.status === 'TOO_MANY_REQUESTS' ? 'RATE-LIMITED' : 'REPORTED' };
|
return { recentlyReported: true, timeDifference: Date.now() - lastReport.timestamp, reason: lastReport.status === 'TOO_MANY_REQUESTS' ? 'RATE-LIMITED' : 'REPORTED' };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +124,7 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
|
||||||
// AbuseIPDB
|
// AbuseIPDB
|
||||||
let cycleId = 1;
|
let cycleId = 1;
|
||||||
while (true) {
|
while (true) {
|
||||||
log('log', `================ New Reporting Cycle v${moduleVersion}; ID: ${cycleId} ================`);
|
log('log', `===================== Reporting Cycle No. ${cycleId} =====================`);
|
||||||
|
|
||||||
const blockedIPEvents = await fetchBlockedIPs();
|
const blockedIPEvents = await fetchBlockedIPs();
|
||||||
if (!blockedIPEvents) {
|
if (!blockedIPEvents) {
|
||||||
|
|
@ -145,13 +151,15 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
|
||||||
if (whitelist.endpoints.includes(event.clientRequestPath)) return log('log', `Skipping ${event.clientRequestPath}...`);
|
if (whitelist.endpoints.includes(event.clientRequestPath)) return log('log', `Skipping ${event.clientRequestPath}...`);
|
||||||
|
|
||||||
const reportedIPs = readReportedIPs();
|
const reportedIPs = readReportedIPs();
|
||||||
const { recentlyReported, timeDifference, reason } = isIPReportedRecently(event.rayName, ip, reportedIPs);
|
const { recentlyReported } = isIPReportedRecently(event.rayName, ip, reportedIPs);
|
||||||
if (recentlyReported) {
|
if (recentlyReported) {
|
||||||
const hoursAgo = Math.floor(timeDifference / (1000 * 60 * 60));
|
// if (process.env.NODE_ENV === 'development') {
|
||||||
const minutesAgo = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
|
// const hoursAgo = Math.floor(timeDifference / (1000 * 60 * 60));
|
||||||
const secondsAgo = Math.floor((timeDifference % (1000 * 60)) / 1000);
|
// const minutesAgo = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
|
||||||
|
// const secondsAgo = Math.floor((timeDifference % (1000 * 60)) / 1000);
|
||||||
|
// log('log', `${ip} was ${reason} ${hoursAgo}h ${minutesAgo}m ${secondsAgo}s ago. Skipping...`);
|
||||||
|
// }
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'development') log('log', `${ip} was ${reason} ${hoursAgo}h ${minutesAgo}m ${secondsAgo}s ago. Skipping...`);
|
|
||||||
cycleSkippedCount++;
|
cycleSkippedCount++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -177,7 +185,7 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
|
||||||
log('log', `- Reported IPs: ${cycleReportedCount}`);
|
log('log', `- Reported IPs: ${cycleReportedCount}`);
|
||||||
log('log', `- Total IPs processed: ${cycleProcessedCount}`);
|
log('log', `- Total IPs processed: ${cycleProcessedCount}`);
|
||||||
log('log', `- Skipped IPs: ${cycleSkippedCount}`);
|
log('log', `- Skipped IPs: ${cycleSkippedCount}`);
|
||||||
log('log', `- Skipped due to image requests: ${cycleImageSkippedCount}`);
|
log('log', `- Ignored image requests: ${cycleImageSkippedCount}`);
|
||||||
log('log', `- Rate-limits: ${cycleErrorCounts.blocked}`);
|
log('log', `- Rate-limits: ${cycleErrorCounts.blocked}`);
|
||||||
log('log', `- Other errors: ${cycleErrorCounts.otherErrors}`);
|
log('log', `- Other errors: ${cycleErrorCounts.otherErrors}`);
|
||||||
log('log', '===================== End of Reporting Cycle =====================');
|
log('log', '===================== End of Reporting Cycle =====================');
|
||||||
|
|
|
||||||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "waf-to-abuseipdb",
|
"name": "waf-to-abuseipdb",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "waf-to-abuseipdb",
|
"name": "waf-to-abuseipdb",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
{
|
{
|
||||||
"name": "waf-to-abuseipdb",
|
"name": "waf-to-abuseipdb",
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"description": "A Node.js project that automates the reporting of incidents detected by Cloudflare WAF to the AbuseIPDB database.",
|
"description": "A Node.js project that automates the reporting of incidents detected by Cloudflare WAF to the AbuseIPDB database.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"abuseipdb",
|
"abuseipdb",
|
||||||
"cloudflare",
|
"cloudflare",
|
||||||
"cloudflare-waf",
|
"cloudflare waf",
|
||||||
"waf",
|
"waf",
|
||||||
"reporting",
|
"reporting",
|
||||||
"abuseipdb-reporting",
|
"abuseipdb reporting",
|
||||||
"node-abuseipdb"
|
"node abuseipdb"
|
||||||
],
|
],
|
||||||
"homepage": "https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB",
|
"homepage": "https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
const CYCLE_INTERVAL = process.env.NODE_ENV === 'production' ?
|
const CYCLE_INTERVAL = process.env.NODE_ENV === 'production' ?
|
||||||
parseInt(process.env.CYCLE_INTERVAL || '120') * 60 * 1000 : 8 * 1000;
|
parseInt(process.env.CYCLE_INTERVAL || '120') * 60 * 1000 : 8 * 1000;
|
||||||
|
|
||||||
const REPORTED_IP_COOLDOWN_MS = parseInt(process.env.REPORTED_IP_COOLDOWN_MS || '6') * 60 * 60 * 1000;
|
const REPORTED_IP_COOLDOWN = parseInt(process.env.REPORTED_IP_COOLDOWN || '6') * 60 * 60 * 1000;
|
||||||
|
|
||||||
const MAX_URL_LENGTH = parseInt(process.env.MAX_URL_LENGTH || '920');
|
const MAX_URL_LENGTH = parseInt(process.env.MAX_URL_LENGTH || '920');
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ const SEFINEK_API_INTERVAL = process.env.NODE_ENV === 'production' ?
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
CYCLE_INTERVAL,
|
CYCLE_INTERVAL,
|
||||||
REPORTED_IP_COOLDOWN_MS,
|
REPORTED_IP_COOLDOWN,
|
||||||
MAX_URL_LENGTH,
|
MAX_URL_LENGTH,
|
||||||
SUCCESS_COOLDOWN,
|
SUCCESS_COOLDOWN,
|
||||||
IP_REFRESH_INTERVAL,
|
IP_REFRESH_INTERVAL,
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@ module.exports = ({ action, clientAsn, clientASNDescription, clientRequestHTTPPr
|
||||||
{ label: 'Action taken', value: action?.toUpperCase() },
|
{ label: 'Action taken', value: action?.toUpperCase() },
|
||||||
{ label: 'ASN', value: `${clientAsn} (${clientASNDescription})` },
|
{ label: 'ASN', value: `${clientAsn} (${clientASNDescription})` },
|
||||||
{ label: 'Protocol', value: `${clientRequestHTTPProtocol} (${clientRequestHTTPMethodName} method)` },
|
{ label: 'Protocol', value: `${clientRequestHTTPProtocol} (${clientRequestHTTPMethodName} method)` },
|
||||||
{ label: 'Domain', value: clientRequestHTTPHost },
|
{ label: 'Zone', value: clientRequestHTTPHost },
|
||||||
{ label: 'Endpoint', value: clientRequestPath },
|
{ label: 'Endpoint', value: clientRequestPath },
|
||||||
{ label: 'Query', value: clientRequestQuery },
|
{ label: 'Query', value: clientRequestQuery },
|
||||||
{ label: 'Timestamp', value: datetime },
|
{ label: 'Timestamp', value: datetime },
|
||||||
{ label: 'Ray ID', value: rayName },
|
{ label: 'Ray ID', value: rayName },
|
||||||
{ label: 'Rule ID', value: ruleId },
|
// { label: 'Rule ID', value: ruleId },
|
||||||
{ label: 'UA', value: userAgent },
|
{ label: 'UA', value: userAgent },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -22,3 +22,9 @@ ${reportLines.join('\n')}
|
||||||
Report generated by Cloudflare-WAF-To-AbuseIPDB:
|
Report generated by Cloudflare-WAF-To-AbuseIPDB:
|
||||||
https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB`;
|
https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hello! 👋 I'm really glad you're here.
|
||||||
|
* Please do not remove the repository URL in the comment above.
|
||||||
|
* I’d really appreciate it (:
|
||||||
|
*/
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
const subdomains = ['api.', 'cdn.', 'bucket.'];
|
const domains = ['api.', 'cdn.', 'blocklist.sefinek.net', 'bucket.sefinek.net'];
|
||||||
const userAgents = ['Chrome/129', 'Chrome/130', 'Chrome/131', 'Chrome/132', 'StellaLauncher', 'PrepareStella'];
|
const userAgents = ['Chrome/129', 'Chrome/130', 'Chrome/131', 'Chrome/132', 'StellaLauncher', 'PrepareStella'];
|
||||||
const endpoints = ['/api/', '//video', '//js', '//images', '//imgs', 'favicon.ico', 'sitemap.xml', 'robots.txt'];
|
const endpoints = ['/api/', '//video', '//js', '//images', '//imgs', 'favicon.ico', 'sitemap.xml', 'robots.txt'];
|
||||||
|
|
||||||
module.exports = { subdomains, userAgents, endpoints };
|
module.exports = { domains, userAgents, endpoints };
|
||||||
|
|
@ -3,7 +3,7 @@ const query = `query ListFirewallEvents($zoneTag: string, $filter: FirewallEvent
|
||||||
zones(filter: { zoneTag: $zoneTag }) {
|
zones(filter: { zoneTag: $zoneTag }) {
|
||||||
firewallEventsAdaptive(
|
firewallEventsAdaptive(
|
||||||
filter: $filter,
|
filter: $filter,
|
||||||
limit: 1500,
|
limit: 1000,
|
||||||
orderBy: [datetime_DESC]
|
orderBy: [datetime_DESC]
|
||||||
) {
|
) {
|
||||||
action
|
action
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,17 @@ module.exports = async () => {
|
||||||
const reportedIPs = (readReportedIPs() || []).filter(x =>
|
const reportedIPs = (readReportedIPs() || []).filter(x =>
|
||||||
x.status === 'REPORTED' &&
|
x.status === 'REPORTED' &&
|
||||||
x.ip !== clientIp.getAddress() &&
|
x.ip !== clientIp.getAddress() &&
|
||||||
x.hostname !== 'blocklist.sefinek.net' && // Domain
|
!x.sefinekAPI &&
|
||||||
!whitelist.subdomains.some(subdomain => x.clientRequestHTTPHost?.includes(subdomain)) && // Subdomains
|
(
|
||||||
!whitelist.userAgents.some(ua => x.userAgent?.includes(ua)) && // User-agents
|
x.source === 'securitylevel' ||
|
||||||
!whitelist.endpoints.some(endpoint => x.clientRequestPath?.includes(endpoint)) && // Endpoints
|
x.source === 'badscore' ||
|
||||||
|
(
|
||||||
!(/crawler|spider|bot/gi).test(x.userAgent) &&
|
!(/crawler|spider|bot/gi).test(x.userAgent) &&
|
||||||
!x.sefinekAPI
|
!whitelist.domains.some(subdomain => x.clientRequestHTTPHost?.includes(subdomain)) &&
|
||||||
|
!whitelist.userAgents.some(ua => x.userAgent?.includes(ua)) &&
|
||||||
|
!whitelist.endpoints.some(endpoint => x.clientRequestPath?.includes(endpoint))
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!reportedIPs.length) return;
|
if (!reportedIPs.length) return;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue