This commit is contained in:
Sefinek 2025-02-02 01:51:39 +01:00
parent a0eb452044
commit 73c8a834d3
22 changed files with 214 additions and 212 deletions

View file

@ -1,42 +0,0 @@
# production or development
NODE_ENV=production
############################### TOKENS ###############################
# Cloudflare (https://dash.cloudflare.com/profile/api-tokens)
CLOUDFLARE_ZONE_ID=00000000000000000000000000000000
CLOUDFLARE_API_KEY=0000000000000000000000000000000000000000
# AbuseIPDB (https://www.abuseipdb.com/account/api)
ABUSEIPDB_API_KEY=00000000000000000000000000000000000000000000000000000000000000000000000000000000
############################### CYCLES ###############################
# Main interval (in minutes) of each cycle. For production 2h; development 8s.
CYCLE_INTERVAL=120
# 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.
REPORTED_IP_COOLDOWN=7
# The maximum URI length that can be reported to AbuseIPDB.
# If Cloudflare returns a longer URI, the API request will fail.
MAX_URL_LENGTH=920
# Additional delay (in miliseconds) after each successful IP report to avoid overloading the AbuseIPDB API.
SUCCESS_COOLDOWN=80
# Interval for refreshing your IP address (in minutes).
# This ensures that WAF violations originating from your IP address are not reported to AbuseIPDB.
IP_REFRESH_INTERVAL=80
############################### SEFINEK API ###############################
# 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
# 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.
SEFINEK_API_INTERVAL=1
# Sefinek API v2 URL
SEFINEK_API_URL=https://api.sefinek.net/api/v2

2
.gitignore vendored
View file

@ -1,3 +1,3 @@
node_modules
.env
config.js
reported_ips.csv

View file

@ -22,7 +22,6 @@ Triggered Cloudflare WAF (securitylevel) from T1.
Action taken: MANAGED_CHALLENGE
ASN: 53667 (PONYNET)
Protocol: HTTP/1.0 (method GET)
Zone: blocklist.sefinek.net
Endpoint: /
Timestamp: 2024-11-09T19:20:18Z
Ray ID: 8e0028cb79ab3a96
@ -47,33 +46,40 @@ https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB
```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.
3. Create a new configuration file.
```bash
cp config.default.js config.js
```
4. Paste the tokens into the `config.js` file. Make sure that `NODE_ENV` is set to `production`.
```bash
nano config.js
```
5. Run the script.
```bash
node .
```
5. If you want to run the process 24/7, install the [PM2](https://www.npmjs.com/package/pm2) module.
6. If you want to run the process 24/7, install the [PM2](https://www.npmjs.com/package/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.
7. 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.
8. 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.
9. Save a snapshot of the currently running `Node.js` processes.
```bash
pm2 save
```
9. Add `PM2` to startup.
10. Add `PM2` to startup.
```bash
pm2 startup
```
10. Execute the command generated by PM2, e.g.:
11. 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. Thats it! Monitor logs using the `pm2 logs` command.
12. Thats it! Monitor logs using the `pm2 logs` command.
## 🔤 How to Get Tokens?
@ -100,4 +106,4 @@ I'm not particularly fond of Python and usually try to avoid using this programm
## 📑 MIT License
Copyright 2024 © by [Sefinek](https://sefinek.net). All Rights Reserved.
Copyright 2024-2025 © by [Sefinek](https://sefinek.net). All Rights Reserved.

64
config.default.js Normal file
View file

@ -0,0 +1,64 @@
exports.CONFIG = {
MAIN: {
NODE_ENV: 'production', // Environment mode: 'production' or 'development'
CLOUDFLARE_ZONE_ID: '00000000000000000000000000000000', // https://dash.cloudflare.com/profile/api-tokens
CLOUDFLARE_API_KEY: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', // API key for Cloudflare access
ABUSEIPDB_API_KEY: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', // API key for reporting malicious IPs to AbuseIPDB
},
CYCLES: {
// Main interval (in minutes) of each cycle
CYCLE_INTERVAL: 120 * 60 * 1000,
// 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.
REPORTED_IP_COOLDOWN: 6 * 60 * 60 * 1000,
// The maximum URI length that can be reported to AbuseIPDB.
// If Cloudflare returns a longer URI, the API request will fail.
MAX_URL_LENGTH: 780,
// Additional delay (in milliseconds) after each successful IP report to avoid overloading the AbuseIPDB API.
SUCCESS_COOLDOWN: 30,
// Interval for refreshing your IP address (in minutes).
// This ensures that WAF violations originating from your IP address are not reported to AbuseIPDB.
IP_REFRESH_INTERVAL: 80 * 60 * 1000,
},
SEFINEK_API: {
// Report IP addresses to api.sefinek.net to support the development of the repository at https://github.com/sefinek/Malicious-IP-Addresses. SECRET_TOKEN is required if true.
REPORT_TO_SEFIN_API: true,
// Secret key for api.sefinek.net
SECRET_TOKEN: 'HKKAUZHTDAH7W87SyL6XsWkV8UeUFVA9VvvXhn6H9Wn6kfDW6ZsXCtbahmkaYcLbxZGyrAKPmSkXb3AJ6pCU3VuDyTjUSehMyDZ',
// How often should the log (reported_ips.csv) be analyzed and sent to the Sefinek API? In hours.
INTERVAL: 60 * 60 * 1000, // Frequency for analyzing and submitting logs to the Sefinek API
},
};
exports.GENERATE_COMMENT = ({ action, clientAsn, clientASNDescription, clientRequestHTTPProtocol, clientRequestHTTPMethodName, clientRequestHTTPHost, clientRequestPath, clientRequestQuery, datetime, rayName, ruleId, userAgent, source, clientCountryName }) => {
const fields = [
{ label: 'Action taken', value: action?.toUpperCase() },
{ label: 'ASN', value: `${clientAsn} (${clientASNDescription})` },
{ label: 'Protocol', value: `${clientRequestHTTPProtocol} (${clientRequestHTTPMethodName} method)` },
// { label: 'Zone', value: clientRequestHTTPHost },
{ label: 'Endpoint', value: clientRequestPath },
{ label: 'Query', value: clientRequestQuery },
{ label: 'Timestamp', value: datetime },
{ label: 'Ray ID', value: rayName },
// { label: 'Rule ID', value: ruleId },
{ label: 'UA', value: userAgent || 'Empty string' },
];
const reportLines = fields
.filter(({ value }) => value)
.map(({ label, value }) => `${label}: ${value}`);
return `Triggered Cloudflare WAF (${source}) from ${clientCountryName}.
${reportLines.join('\n')}
Report generated by Cloudflare-WAF-To-AbuseIPDB:
https://github.com/sefinek/Cloudflare-WAF-To-AbuseIPDB`; // Please do not remove the repository URL. I'd really appreciate it (:
};

View file

@ -1,17 +1,14 @@
require('dotenv').config();
const { axios } = require('./services/axios.js');
const { CYCLE_INTERVAL, REPORTED_IP_COOLDOWN, MAX_URL_LENGTH, SUCCESS_COOLDOWN, SEFINEK_API_INTERVAL, REPORT_TO_SEFINEK_API } = require('./scripts/config.js');
const axios = require('./services/axios.js');
const { CONFIG, GENERATE_COMMENT } = require('./config.js');
const PAYLOAD = require('./services/payload.js');
const generateComment = require('./scripts/generateComment.js');
const SefinekAPI = require('./services/SefinekAPI.js');
const isImageRequest = require('./scripts/isImageRequest.js');
const headers = require('./scripts/headers.js');
const isImageRequest = require('./utils/isImageRequest.js');
const headers = require('./utils/headers.js');
const { logToCSV, readReportedIPs, wasImageRequestLogged } = require('./services/csv.js');
const formatDelay = require('./scripts/formatDelay.js');
const clientIp = require('./services/clientIp.js');
const whitelist = require('./scripts/whitelist.js');
const log = require('./scripts/log.js');
const formatDelay = require('./utils/formatDelay.js');
const fetchServerIP = require('./services/fetchServerIP.js');
const whitelist = require('./utils/whitelist.js');
const log = require('./utils/log.js');
const fetchBlockedIPs = async () => {
try {
@ -19,7 +16,7 @@ const fetchBlockedIPs = async () => {
const events = data?.data?.viewer?.zones[0]?.firewallEventsAdaptive;
if (events) {
const filtered = events.filter(x =>
x.ip !== clientIp.getAddress() &&
x.ip !== fetchServerIP() &&
(
x.source === 'securitylevel' ||
x.source === 'badscore' ||
@ -52,7 +49,7 @@ const isIPReportedRecently = (rayId, ip, reportedIPs) => {
return latest;
}, null);
if (lastReport && (Date.now() - lastReport.timestamp) < REPORTED_IP_COOLDOWN) {
if (lastReport && (Date.now() - lastReport.timestamp) < CONFIG.CYCLES.REPORTED_IP_COOLDOWN) {
return { recentlyReported: true, timeDifference: Date.now() - lastReport.timestamp, reason: lastReport.status === 'TOO_MANY_REQUESTS' ? 'RATE-LIMITED' : 'REPORTED' };
}
@ -66,13 +63,13 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
return false;
}
if (event.clientIP === clientIp.address) {
if (event.clientIP === fetchServerIP()) {
logToCSV(event.rayName, event.clientIP, country, hostname, endpoint, event.userAgent, event.action, 'YOUR_IP_ADDRESS');
log(0, `Your IP address (${event.clientIP}) was unexpectedly received from Cloudflare. URI: ${uri}`);
return false;
}
if (uri.length > MAX_URL_LENGTH) {
if (uri.length > CONFIG.CYCLES.MAX_URL_LENGTH) {
logToCSV(event.rayName, event.clientIP, country, hostname, endpoint, event.userAgent, event.action, 'URI_TOO_LONG');
// log(0, `URI too long ${event.clientIP}; Received: ${uri}`);
return false;
@ -82,7 +79,7 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
await axios.post('https://api.abuseipdb.com/api/v2/report', {
ip: event.clientIP,
categories: '19',
comment: generateComment(event),
comment: GENERATE_COMMENT(event),
}, { headers: headers.ABUSEIPDB });
logToCSV(event.rayName, event.clientIP, country, hostname, endpoint, event.userAgent, event.action, 'REPORTED');
@ -105,15 +102,14 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
(async () => {
log(0, 'Loading data, please wait...');
await clientIp.fetchIPAddress();
// Sefinek API
if (REPORT_TO_SEFINEK_API && SEFINEK_API_INTERVAL && process.env.SEFINEK_API_SECRET) {
setInterval(SefinekAPI, SEFINEK_API_INTERVAL);
if (CONFIG.SEFINEK_API.REPORT_TO_SEFIN_API && CONFIG.SEFINEK_API.INTERVAL && CONFIG.SEFINEK_API.SECRET_TOKEN) {
setInterval(SefinekAPI, CONFIG.SEFINEK_API.INTERVAL);
}
// Ready
if (process.env.NODE_ENV === 'production') {
if (CONFIG.MAIN.NODE_ENV === 'production') {
try {
process.send('ready');
} catch (err) {
@ -132,7 +128,7 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
continue;
}
const userIp = clientIp.getAddress();
const userIp = fetchServerIP();
if (!userIp) log(1, `Your IP address is missing! Received: ${userIp}`);
let cycleImageSkippedCount = 0, cycleProcessedCount = 0, cycleReportedCount = 0, cycleSkippedCount = 0;
@ -153,7 +149,7 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
const reportedIPs = readReportedIPs();
const { recentlyReported } = isIPReportedRecently(event.rayName, ip, reportedIPs);
if (recentlyReported) {
// if (process.env.NODE_ENV === 'development') {
// if (MAIN.NODE_ENV === 'development') {
// const hoursAgo = Math.floor(timeDifference / (1000 * 60 * 60));
// const minutesAgo = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
// const secondsAgo = Math.floor((timeDifference % (1000 * 60)) / 1000);
@ -178,7 +174,7 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
const wasReported = await reportIP(event, `${event.clientRequestHTTPHost}${event.clientRequestPath}`, event.clientCountryName, event.clientRequestHTTPHost, event.clientRequestPath, cycleErrorCounts);
if (wasReported) {
cycleReportedCount++;
await new Promise(resolve => setTimeout(resolve, SUCCESS_COOLDOWN));
await new Promise(resolve => setTimeout(resolve, CONFIG.CYCLES.SUCCESS_COOLDOWN));
}
}
@ -190,8 +186,8 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
log(0, `- Other errors: ${cycleErrorCounts.otherErrors}`);
log(0, '===================== End of Reporting Cycle =====================');
log(0, `Waiting ${formatDelay(CYCLE_INTERVAL)}...`);
log(0, `Waiting ${formatDelay(CONFIG.CYCLES.CYCLE_INTERVAL)}...`);
cycleId++;
await new Promise(resolve => setTimeout(resolve, CYCLE_INTERVAL));
await new Promise(resolve => setTimeout(resolve, CONFIG.CYCLES.CYCLE_INTERVAL));
}
})();

35
package-lock.json generated
View file

@ -1,26 +1,26 @@
{
"name": "cf-waf-to-abuseipdb",
"version": "1.2.3",
"version": "1.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "cf-waf-to-abuseipdb",
"version": "1.2.3",
"version": "1.3.0",
"license": "MIT",
"dependencies": {
"axios": "^1.7.9",
"dotenv": "^16.4.7"
"ipaddr.js": "^2.2.0"
},
"devDependencies": {
"@eslint/js": "^9.18.0",
"@eslint/js": "^9.19.0",
"globals": "^15.14.0"
}
},
"node_modules/@eslint/js": {
"version": "9.18.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.18.0.tgz",
"integrity": "sha512-fK6L7rxcq6/z+AaQMtiFTkvbHkBLNlwyRxHpKawP0x3u9+NC6MQTnFW+AdpwC6gfHTW0051cokQgtTN2FqlxQA==",
"version": "9.19.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.19.0.tgz",
"integrity": "sha512-rbq9/g38qjfqFLOVPvwjIvFFdNziEC5S65jmjPw5r6A//QH+W91akh9irMwjDN8zKUTak6W9EsAv4m/7Wnw0UQ==",
"dev": true,
"license": "MIT",
"engines": {
@ -65,18 +65,6 @@
"node": ">=0.4.0"
}
},
"node_modules/dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://dotenvx.com"
}
},
"node_modules/follow-redirects": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
@ -124,6 +112,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ipaddr.js": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz",
"integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==",
"license": "MIT",
"engines": {
"node": ">= 10"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",

View file

@ -1,6 +1,6 @@
{
"name": "cf-waf-to-abuseipdb",
"version": "1.2.3",
"version": "1.3.0",
"description": "Node.js script for automatically reporting incidents to AbuseIPDB using data obtained from Cloudflare WAF.",
"keywords": [
"abuseipdb",
@ -21,6 +21,7 @@
},
"license": "MIT",
"author": "Sefinek <contact@sefinek.net> (https://sefinek.net)",
"type": "commonjs",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
@ -28,10 +29,10 @@
},
"dependencies": {
"axios": "^1.7.9",
"dotenv": "^16.4.7"
"ipaddr.js": "^2.2.0"
},
"devDependencies": {
"@eslint/js": "^9.18.0",
"@eslint/js": "^9.19.0",
"globals": "^15.14.0"
}
}

View file

@ -1,25 +0,0 @@
const CYCLE_INTERVAL = process.env.NODE_ENV === 'production' ?
parseInt(process.env.CYCLE_INTERVAL || '120') * 60 * 1000 : 8 * 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 SUCCESS_COOLDOWN = parseInt(process.env.SUCCESS_COOLDOWN || '200');
const IP_REFRESH_INTERVAL = parseInt(process.env.IP_REFRESH_INTERVAL || '80') * 60 * 1000;
const REPORT_TO_SEFINEK_API = process.env.REPORT_TO_SEFINEK_API === 'true';
const SEFINEK_API_INTERVAL = process.env.NODE_ENV === 'production' ?
parseInt(process.env.SEFINEK_API_INTERVAL || '1') * 60 * 60 * 1000 : 5 * 1000;
module.exports = {
CYCLE_INTERVAL,
REPORTED_IP_COOLDOWN,
MAX_URL_LENGTH,
SUCCESS_COOLDOWN,
IP_REFRESH_INTERVAL,
REPORT_TO_SEFINEK_API,
SEFINEK_API_INTERVAL,
};

View file

@ -1,30 +0,0 @@
module.exports = ({ action, clientAsn, clientASNDescription, clientRequestHTTPProtocol, clientRequestHTTPMethodName, clientRequestHTTPHost, clientRequestPath, clientRequestQuery, datetime, rayName, ruleId, userAgent, source, clientCountryName }) => {
const fields = [
{ label: 'Action taken', value: action?.toUpperCase() },
{ label: 'ASN', value: `${clientAsn} (${clientASNDescription})` },
{ label: 'Protocol', value: `${clientRequestHTTPProtocol} (${clientRequestHTTPMethodName} method)` },
// { label: 'Zone', value: clientRequestHTTPHost },
{ label: 'Endpoint', value: clientRequestPath },
{ label: 'Query', value: clientRequestQuery },
{ label: 'Timestamp', value: datetime },
{ label: 'Ray ID', value: rayName },
// { label: 'Rule ID', value: ruleId },
{ label: 'UA', value: userAgent || 'Empty string' },
];
const reportLines = fields
.filter(({ value }) => value)
.map(({ label, value }) => `${label}: ${value}`);
return `Triggered Cloudflare WAF (${source}) from ${clientCountryName}.
${reportLines.join('\n')}
Report generated by 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.
* Id really appreciate it (:
*/

View file

@ -1,17 +0,0 @@
const { name, version, homepage } = require('../package.json');
const UserAgent = `Mozilla/5.0 (compatible; ${name}/${version}; +${homepage})`;
const CLOUDFLARE = {
'User-Agent': UserAgent,
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.CLOUDFLARE_API_KEY}`,
};
const ABUSEIPDB = {
'User-Agent': UserAgent,
'Content-Type': 'application/json',
'Key': process.env.ABUSEIPDB_API_KEY,
};
module.exports = { UserAgent, CLOUDFLARE, ABUSEIPDB };

View file

@ -1,15 +1,14 @@
const { axios } = require('./axios.js');
const axios = require('./axios.js');
const { readReportedIPs, updateSefinekAPIInCSV } = require('./csv.js');
const log = require('../scripts/log.js');
const clientIp = require('./clientIp.js');
const whitelist = require('../scripts/whitelist.js');
const API_URL = `${process.env.SEFINEK_API_URL}/cloudflare-waf-abuseipdb/post`;
const log = require('../utils/log.js');
const fetchServerIP = require('./fetchServerIP.js');
const whitelist = require('../utils/whitelist.js');
const { MAIN } = require('../config.js').CONFIG;
module.exports = async () => {
const reportedIPs = (readReportedIPs() || []).filter(x =>
x.status === 'REPORTED' &&
x.ip !== clientIp.getAddress() &&
x.ip !== fetchServerIP() &&
!x.sefinekAPI &&
(
x.source === 'securitylevel' ||
@ -35,7 +34,7 @@ module.exports = async () => {
if (!uniqueLogs.length) return log(0, 'No unique IPs to send to Sefinek API');
try {
const res = await axios.post(API_URL, {
const res = await axios.post('https://api.sefinek.net/api/v2/cloudflare-waf-abuseipdb/post', {
reportedIPs: uniqueLogs.map(ip => ({
rayId: ip.rayId,
ip: ip.ip,
@ -45,7 +44,7 @@ module.exports = async () => {
country: ip.country,
timestamp: ip.timestamp,
})),
}, { headers: { 'Authorization': process.env.SEFINEK_API_SECRET } });
}, { headers: { 'Authorization': MAIN.SECRET_TOKEN } });
log(0, `Successfully sent ${uniqueLogs.length} logs to Sefinek API. Status: ${res.status}`);

View file

@ -1,8 +1,13 @@
const axios = require('axios');
const { UserAgent } = require('../scripts/headers.js');
const { version } = require('../package.json');
const { UserAgent } = require('../utils/headers.js');
axios.defaults.headers.common['User-Agent'] = UserAgent;
axios.defaults.timeout = 25000;
axios.defaults.headers.common = {
'User-Agent': UserAgent,
'Accept': 'application/json',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
};
module.exports = { axios, moduleVersion: version };
axios.defaults.timeout = 30000;
module.exports = axios;

View file

@ -1,23 +0,0 @@
const { axios } = require('./axios.js');
const { IP_REFRESH_INTERVAL } = require('../scripts/config.js');
const log = require('../scripts/log.js');
let address = null; // Holds the IP address
const fetchIPAddress = async () => {
try {
const { data } = await axios.get('https://api.sefinek.net/api/v2/ip');
if (data?.success) {
address = data.message;
} else {
log(2, 'Failed to retrieve your IP');
}
} catch (err) {
log(2, 'Error fetching your IP:', err.stack);
}
};
setInterval(fetchIPAddress, IP_REFRESH_INTERVAL);
module.exports = { fetchIPAddress, getAddress: () => address };

View file

@ -1,6 +1,6 @@
const fs = require('node:fs');
const path = require('node:path');
const log = require('../scripts/log.js');
const log = require('../utils/log.js');
const CSV_FILE_PATH = path.join(__dirname, '..', 'reported_ips.csv');
const MAX_CSV_SIZE_BYTES = 3 * 1024 * 1024; // 3 MB

41
services/fetchServerIP.js Normal file
View file

@ -0,0 +1,41 @@
const { networkInterfaces } = require('node:os');
const axios = require('./axios.js');
const isLocalIP = require('../utils/isLocalIP.js');
const log = require('../utils/log.js');
const { CYCLES } = require('../config.js').CONFIG;
const ipAddrList = new Set();
const fetchIPv4Address = async () => {
try {
const { data } = await axios.get('https://api.sefinek.net/api/v2/ip');
if (data?.success && data?.message) ipAddrList.add(data.message);
} catch (err) {
log(2, `Error fetching IPv4 address: ${err.message}`);
}
};
const fetchIPv6Address = () => {
try {
Object.values(networkInterfaces()).flat().forEach(({ address, internal }) => {
if (!internal && address && !isLocalIP(address)) ipAddrList.add(address);
});
} catch (err) {
log(2, `Error fetching IPv6 address: ${err.message}`);
}
};
const fetchServerIPs = async () => {
ipAddrList.clear();
await fetchIPv4Address();
fetchIPv6Address();
};
(async () => {
await fetchServerIPs();
setInterval(fetchServerIPs, CYCLES.IP_REFRESH_INTERVAL);
// console.debug(ipAddrList);
})();
module.exports = () => Array.from(ipAddrList);

View file

@ -1,3 +1,5 @@
const { MAIN } = require('../config.js').CONFIG;
const query = `query ListFirewallEvents($zoneTag: string, $filter: FirewallEventsAdaptiveFilter_InputObject) {
viewer {
zones(filter: { zoneTag: $zoneTag }) {
@ -28,7 +30,7 @@ const query = `query ListFirewallEvents($zoneTag: string, $filter: FirewallEvent
module.exports = () => {
const variables = {
zoneTag: process.env.CLOUDFLARE_ZONE_ID,
zoneTag: MAIN.CLOUDFLARE_ZONE_ID,
filter: {
datetime_geq: new Date(Date.now() - (60 * 60 * 12 * 1000)).toISOString(),
// datetime_leq: new Date(Date.now() - (60 * 60 * 8 * 1000)).toISOString(),

18
utils/headers.js Normal file
View file

@ -0,0 +1,18 @@
const { MAIN } = require('../config.js').CONFIG;
const { version, homepage } = require('../package.json');
const UserAgent = `Mozilla/5.0 (compatible; Cloudflare-WAF-To-AbuseIPDB/${version}; +${homepage})`;
const CLOUDFLARE = {
'User-Agent': UserAgent,
'Content-Type': 'application/json',
'Authorization': `Bearer ${MAIN.CLOUDFLARE_API_KEY}`,
};
const ABUSEIPDB = {
'User-Agent': UserAgent,
'Content-Type': 'application/json',
'Key': MAIN.ABUSEIPDB_API_KEY,
};
module.exports = { UserAgent, CLOUDFLARE, ABUSEIPDB };

10
utils/isLocalIP.js Normal file
View file

@ -0,0 +1,10 @@
const ipaddr = require('ipaddr.js');
module.exports = ip => {
const range = ipaddr.parse(ip).range();
return [
'unspecified', 'multicast', 'linkLocal', 'loopback', 'reserved', 'benchmarking',
'amt', 'broadcast', 'carrierGradeNat', 'private', 'as112', 'uniqueLocal',
'ipv4Mapped', 'rfc6145', '6to4', 'teredo', 'as112v6', 'orchid2', 'droneRemoteIdProtocolEntityTags',
].includes(range);
};