Update
This commit is contained in:
parent
5860aba631
commit
c09400eb82
6 changed files with 28 additions and 62 deletions
|
|
@ -28,10 +28,10 @@ exports.CONFIG = {
|
||||||
|
|
||||||
SEFINEK_API: {
|
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 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,
|
REPORT_TO_SEFIN_API: false,
|
||||||
|
|
||||||
// Secret key for api.sefinek.net
|
// Secret key for api.sefinek.net
|
||||||
SECRET_TOKEN: 'HKKAUZHTDAH7W87SyL6XsWkV8UeUFVA9VvvXhn6H9Wn6kfDW6ZsXCtbahmkaYcLbxZGyrAKPmSkXb3AJ6pCU3VuDyTjUSehMyDZ',
|
SECRET_TOKEN: '',
|
||||||
|
|
||||||
// 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.
|
||||||
INTERVAL: 60 * 60 * 1000, // Frequency for analyzing and submitting logs to the Sefinek API
|
INTERVAL: 60 * 60 * 1000, // Frequency for analyzing and submitting logs to the Sefinek API
|
||||||
|
|
|
||||||
37
index.js
37
index.js
|
|
@ -2,13 +2,13 @@ const axios = require('./services/axios.js');
|
||||||
const { CONFIG, GENERATE_COMMENT } = require('./config.js');
|
const { CONFIG, GENERATE_COMMENT } = require('./config.js');
|
||||||
const PAYLOAD = require('./services/payload.js');
|
const PAYLOAD = require('./services/payload.js');
|
||||||
const SefinekAPI = require('./services/SefinekAPI.js');
|
const SefinekAPI = require('./services/SefinekAPI.js');
|
||||||
const isImageRequest = require('./utils/isImageRequest.js');
|
|
||||||
const headers = require('./utils/headers.js');
|
const headers = require('./utils/headers.js');
|
||||||
const { logToCSV, readReportedIPs, wasImageRequestLogged } = require('./services/csv.js');
|
const { logToCSV, readReportedIPs } = require('./services/csv.js');
|
||||||
const formatDelay = require('./utils/formatDelay.js');
|
const formatDelay = require('./utils/formatDelay.js');
|
||||||
const fetchServerIP = require('./services/fetchServerIP.js');
|
const fetchServerIP = require('./services/fetchServerIP.js');
|
||||||
const whitelist = require('./utils/whitelist.js');
|
const whitelist = require('./utils/whitelist.js');
|
||||||
const log = require('./utils/log.js');
|
const log = require('./utils/log.js');
|
||||||
|
const imgExtensions = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.svg', '.webp'];
|
||||||
|
|
||||||
const fetchBlockedIPs = async () => {
|
const fetchBlockedIPs = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -17,15 +17,9 @@ const fetchBlockedIPs = async () => {
|
||||||
if (events) {
|
if (events) {
|
||||||
const filtered = events.filter(x =>
|
const filtered = events.filter(x =>
|
||||||
x.ip !== fetchServerIP() &&
|
x.ip !== fetchServerIP() &&
|
||||||
(
|
!imgExtensions.some(ext => x.clientRequestPath.endsWith(ext)) &&
|
||||||
x.source === 'securitylevel' ||
|
|
||||||
x.source === 'badscore' ||
|
|
||||||
(
|
|
||||||
!whitelist.domains.some(subdomain => x.clientRequestHTTPHost?.includes(subdomain)) &&
|
!whitelist.domains.some(subdomain => x.clientRequestHTTPHost?.includes(subdomain)) &&
|
||||||
!whitelist.userAgents.some(ua => x.userAgent?.includes(ua)) &&
|
|
||||||
!whitelist.endpoints.some(endpoint => x.clientRequestPath?.includes(endpoint))
|
!whitelist.endpoints.some(endpoint => x.clientRequestPath?.includes(endpoint))
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
log(0, `Fetched ${events.length} (filtered ${filtered.length}) events from Cloudflare`);
|
log(0, `Fetched ${events.length} (filtered ${filtered.length}) events from Cloudflare`);
|
||||||
|
|
@ -92,7 +86,7 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
|
||||||
log(0, `429 for ${event.clientIP} (${event.rayName}); Endpoint: ${endpoint}`);
|
log(0, `429 for ${event.clientIP} (${event.rayName}); Endpoint: ${endpoint}`);
|
||||||
cycleErrorCounts.blocked++;
|
cycleErrorCounts.blocked++;
|
||||||
} else {
|
} else {
|
||||||
log(2, `Error ${err.response?.status} while reporting ${event.clientIP}; URI: ${uri}; (${err.response?.data || err.message})`);
|
log(2, `Error ${err.response?.status} while reporting ${event.clientIP}; URI: ${uri}; ${err.response?.data?.errors[0]?.detail || JSON.stringify(err.response?.data) || err.message}`);
|
||||||
cycleErrorCounts.otherErrors++;
|
cycleErrorCounts.otherErrors++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,6 +98,8 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
|
||||||
log(0, 'Loading data, please wait...');
|
log(0, 'Loading data, please wait...');
|
||||||
|
|
||||||
// Sefinek API
|
// Sefinek API
|
||||||
|
await SefinekAPI();
|
||||||
|
return;
|
||||||
if (CONFIG.SEFINEK_API.REPORT_TO_SEFIN_API && CONFIG.SEFINEK_API.INTERVAL && CONFIG.SEFINEK_API.SECRET_TOKEN) {
|
if (CONFIG.SEFINEK_API.REPORT_TO_SEFIN_API && CONFIG.SEFINEK_API.INTERVAL && CONFIG.SEFINEK_API.SECRET_TOKEN) {
|
||||||
setInterval(SefinekAPI, CONFIG.SEFINEK_API.INTERVAL);
|
setInterval(SefinekAPI, CONFIG.SEFINEK_API.INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
@ -128,17 +124,16 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userIp = fetchServerIP();
|
const serverIP = fetchServerIP();
|
||||||
if (!userIp) log(1, `Your IP address is missing! Received: ${userIp}`);
|
if (!serverIP) log(1, `Server IP address is missing! Received: ${serverIP}`);
|
||||||
|
|
||||||
let cycleImageSkippedCount = 0, cycleProcessedCount = 0, cycleReportedCount = 0, cycleSkippedCount = 0;
|
let cycleProcessedCount = 0, cycleReportedCount = 0, cycleSkippedCount = 0;
|
||||||
const cycleErrorCounts = { blocked: 0, otherErrors: 0 };
|
const cycleErrorCounts = { blocked: 0, otherErrors: 0 };
|
||||||
let imageRequestLogged = false;
|
|
||||||
|
|
||||||
for (const event of blockedIPEvents) {
|
for (const event of blockedIPEvents) {
|
||||||
cycleProcessedCount++;
|
cycleProcessedCount++;
|
||||||
const ip = event.clientIP;
|
const ip = event.clientIP;
|
||||||
if (ip === userIp) {
|
if (ip === serverIP) {
|
||||||
log(0, `The IP address ${ip} belongs to this machine. Ignoring...`);
|
log(0, `The IP address ${ip} belongs to this machine. Ignoring...`);
|
||||||
cycleSkippedCount++;
|
cycleSkippedCount++;
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -160,17 +155,6 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isImageRequest(event.clientRequestPath)) {
|
|
||||||
cycleImageSkippedCount++;
|
|
||||||
if (!wasImageRequestLogged(ip, reportedIPs)) {
|
|
||||||
if (imageRequestLogged) continue;
|
|
||||||
log(0, 'Skipping image requests in this cycle...');
|
|
||||||
imageRequestLogged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wasReported = await reportIP(event, `${event.clientRequestHTTPHost}${event.clientRequestPath}`, event.clientCountryName, event.clientRequestHTTPHost, event.clientRequestPath, cycleErrorCounts);
|
const wasReported = await reportIP(event, `${event.clientRequestHTTPHost}${event.clientRequestPath}`, event.clientCountryName, event.clientRequestHTTPHost, event.clientRequestPath, cycleErrorCounts);
|
||||||
if (wasReported) {
|
if (wasReported) {
|
||||||
cycleReportedCount++;
|
cycleReportedCount++;
|
||||||
|
|
@ -181,7 +165,6 @@ const reportIP = async (event, uri, country, hostname, endpoint, cycleErrorCount
|
||||||
log(0, `- Reported IPs: ${cycleReportedCount}`);
|
log(0, `- Reported IPs: ${cycleReportedCount}`);
|
||||||
log(0, `- Total IPs processed: ${cycleProcessedCount}`);
|
log(0, `- Total IPs processed: ${cycleProcessedCount}`);
|
||||||
log(0, `- Skipped IPs: ${cycleSkippedCount}`);
|
log(0, `- Skipped IPs: ${cycleSkippedCount}`);
|
||||||
log(0, `- Ignored image requests: ${cycleImageSkippedCount}`);
|
|
||||||
log(0, `- Rate-limits: ${cycleErrorCounts.blocked}`);
|
log(0, `- Rate-limits: ${cycleErrorCounts.blocked}`);
|
||||||
log(0, `- Other errors: ${cycleErrorCounts.otherErrors}`);
|
log(0, `- Other errors: ${cycleErrorCounts.otherErrors}`);
|
||||||
log(0, '===================== End of Reporting Cycle =====================');
|
log(0, '===================== End of Reporting Cycle =====================');
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,10 @@ const axios = require('./axios.js');
|
||||||
const { readReportedIPs, updateSefinekAPIInCSV } = require('./csv.js');
|
const { readReportedIPs, updateSefinekAPIInCSV } = require('./csv.js');
|
||||||
const log = require('../utils/log.js');
|
const log = require('../utils/log.js');
|
||||||
const fetchServerIP = require('./fetchServerIP.js');
|
const fetchServerIP = require('./fetchServerIP.js');
|
||||||
const whitelist = require('../utils/whitelist.js');
|
const { SEFINEK_API } = require('../config.js').CONFIG;
|
||||||
const { MAIN } = require('../config.js').CONFIG;
|
|
||||||
|
|
||||||
module.exports = async () => {
|
module.exports = async () => {
|
||||||
const reportedIPs = (readReportedIPs() || []).filter(x =>
|
const reportedIPs = (readReportedIPs() || []).filter(x => x.status === 'REPORTED' && x.ip !== fetchServerIP() && !x.sefinekAPI);
|
||||||
x.status === 'REPORTED' &&
|
|
||||||
x.ip !== fetchServerIP() &&
|
|
||||||
!x.sefinekAPI &&
|
|
||||||
(
|
|
||||||
x.source === 'securitylevel' ||
|
|
||||||
x.source === 'badscore' ||
|
|
||||||
(
|
|
||||||
!(/crawler|spider|bot/gi).test(x.userAgent) &&
|
|
||||||
!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;
|
||||||
|
|
||||||
const seenIPs = new Set();
|
const seenIPs = new Set();
|
||||||
|
|
@ -34,7 +18,8 @@ module.exports = async () => {
|
||||||
if (!uniqueLogs.length) return log(0, 'No unique IPs to send to Sefinek API');
|
if (!uniqueLogs.length) return log(0, 'No unique IPs to send to Sefinek API');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.post('https://api.sefinek.net/api/v2/cloudflare-waf-abuseipdb/post', {
|
// http://127.0.0.1:4010/api/v2/cloudflare-waf-abuseipdb
|
||||||
|
const res = await axios.post('https://api.sefinek.net/api/v2/cloudflare-waf-abuseipdb', {
|
||||||
reportedIPs: uniqueLogs.map(ip => ({
|
reportedIPs: uniqueLogs.map(ip => ({
|
||||||
rayId: ip.rayId,
|
rayId: ip.rayId,
|
||||||
ip: ip.ip,
|
ip: ip.ip,
|
||||||
|
|
@ -44,12 +29,15 @@ module.exports = async () => {
|
||||||
country: ip.country,
|
country: ip.country,
|
||||||
timestamp: ip.timestamp,
|
timestamp: ip.timestamp,
|
||||||
})),
|
})),
|
||||||
}, { headers: { 'Authorization': MAIN.SECRET_TOKEN } });
|
}, { headers: { 'Authorization': SEFINEK_API.SECRET_TOKEN } });
|
||||||
|
|
||||||
log(0, `Successfully sent ${uniqueLogs.length} logs to Sefinek API. Status: ${res.status}`);
|
log(0, `Successfully sent ${uniqueLogs.length} logs to Sefinek API! Status: ${res.status}`);
|
||||||
|
|
||||||
uniqueLogs.forEach(ip => updateSefinekAPIInCSV(ip.rayId, true));
|
uniqueLogs.forEach(ip => updateSefinekAPIInCSV(ip.rayId, true));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log(2, `Failed to send logs to Sefinek API. Status: ${err.response?.status}. Message: ${err.response?.data?.message || err.stack}`);
|
const msg = err.response?.data?.message ?? err.message;
|
||||||
|
if (!msg?.includes('No valid or unique')) {
|
||||||
|
log(2, `Failed to send logs to Sefinek API! Status: ${err.response?.status ?? 'Unknown'}; Message: ${msg}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -76,6 +76,4 @@ const updateSefinekAPIInCSV = (rayId, reportedToSefinekAPI) => {
|
||||||
fs.writeFileSync(CSV_FILE_PATH, updatedLines.join('\n'));
|
fs.writeFileSync(CSV_FILE_PATH, updatedLines.join('\n'));
|
||||||
};
|
};
|
||||||
|
|
||||||
const wasImageRequestLogged = (ip, reportedIPs) => reportedIPs.some(entry => entry.ip === ip && entry.action === 'SKIPPED_IMAGE_REQUEST');
|
module.exports = { logToCSV, readReportedIPs, updateSefinekAPIInCSV };
|
||||||
|
|
||||||
module.exports = { logToCSV, readReportedIPs, updateSefinekAPIInCSV, wasImageRequestLogged };
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
const extensions = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.svg', '.webp'];
|
|
||||||
module.exports = loc => extensions.some(ext => loc.toLowerCase().endsWith(ext));
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
const domains = ['api.', 'cdn.', 'blocklist.sefinek.net', 'bucket.sefinek.net'];
|
const domains = ['blocklist.sefinek.net', 'bucket.sefinek.net'];
|
||||||
const userAgents = ['Chrome/129', 'Chrome/130', 'Chrome/131', 'Chrome/132', 'StellaLauncher', 'PrepareStella'];
|
const endpoints = ['favicon.ico', 'favicon.png', 'sitemap.xml', 'robots.txt'];
|
||||||
const endpoints = ['/api/', '//video', '//js', '//images', '//imgs', 'favicon.ico', 'sitemap.xml', 'robots.txt'];
|
|
||||||
|
|
||||||
module.exports = { domains, userAgents, endpoints };
|
module.exports = { domains, endpoints };
|
||||||
Loading…
Add table
Reference in a new issue