Files
UFW-AbuseIPDB-Reporter/scripts/services/ipFetcher.js
T

85 lines
2.5 KiB
JavaScript

const { networkInterfaces } = require('node:os');
const https = require('node:https');
const { CronJob } = require('cron');
const { axiosSefinek } = require('./axios.js');
const isSpecialPurposeIP = require('../isSpecialPurposeIP.js');
const logger = require('../logger.js');
const { IP_ASSIGNMENT, IP_REFRESH_SCHEDULE, IPv6_SUPPORT } = require('../../config.js').MAIN;
const ipAddresses = new Set();
let ipv6ErrorCount = 0, ipv6ErrorLogged = false;
let isRefreshing = false;
const fetchLocalIPs = () => {
for (const ifaceList of Object.values(networkInterfaces())) {
for (const iface of ifaceList) {
const addr = iface?.address;
if (addr && !iface.internal && !isSpecialPurposeIP(addr).is) ipAddresses.add(addr);
}
}
};
const fetchIPAddress = async (family, attempt = 1) => {
if (family === 0) return fetchLocalIPs();
if (family === 6 && (!IPv6_SUPPORT || ipv6ErrorLogged)) return;
try {
const { data } = await axiosSefinek.get('https://api.sefinek.net/api/v2/ip', {
httpsAgent: new https.Agent({ family }),
});
if (data?.success && data?.message) {
ipAddresses.add(data.message);
if (family === 6 && ipv6ErrorCount > 0) {
logger.success(`IPv6 is now working. It succeeded after ${ipv6ErrorCount} failed attempts.`);
ipv6ErrorCount = 0;
ipv6ErrorLogged = false;
}
} else {
logger.warn(`Unexpected API response: success=${data?.success}, message=${data?.message}`);
}
} catch (err) {
logger.error(`Failed to fetch IPv${family} address (attempt ${attempt}): ${err.message}`);
if (family === 6) {
ipv6ErrorCount++;
if (ipv6ErrorCount >= 6 && !ipv6ErrorLogged) {
ipv6ErrorLogged = true;
logger.warn('IPv6 address could not be retrieved after multiple attempts. Disabling further checks.');
} else if (attempt < 6) {
await new Promise(resolve => setTimeout(resolve, 4000));
await fetchIPAddress(6, attempt + 1);
}
}
}
};
const refreshServerIPs = async () => {
if (isRefreshing) {
logger.info('IP refresh already in progress, skipping...');
return;
}
isRefreshing = true;
logger.info('Trying to fetch your IPv4 and IPv6 address from api.sefinek.net...');
try {
await Promise.all([fetchIPAddress(0), fetchIPAddress(4), fetchIPAddress(6)]);
} catch (err) {
logger.error(`Failed to refresh IP addresses: ${err.message}`);
} finally {
isRefreshing = false;
}
};
(async () => {
if (IP_ASSIGNMENT === 'dynamic') new CronJob(IP_REFRESH_SCHEDULE || '0 */6 * * *', refreshServerIPs, null, true);
})();
module.exports = Object.freeze({
refreshServerIPs,
getServerIPs: () => [...ipAddresses],
});