Files

159 lines
4.3 KiB
JavaScript
Raw Permalink Normal View History

2025-09-02 21:43:00 +10:00
import fs from "node:fs";
import https from "node:https";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { ProxyAgent } from "proxy-agent";
2025-09-02 21:43:00 +10:00
import errs from "../lib/error.js";
import utils from "../lib/utils.js";
import { ipRanges as logger } from "../logger.js";
import internalNginx from "./nginx.js";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const CLOUDFRONT_URL = "https://ip-ranges.amazonaws.com/ip-ranges.json";
const CLOUDFARE_V4_URL = "https://www.cloudflare.com/ips-v4";
const CLOUDFARE_V6_URL = "https://www.cloudflare.com/ips-v6";
2020-02-19 15:55:06 +11:00
2021-12-30 11:50:21 +08:00
const regIpV4 = /^(\d+\.?){4}\/\d+/;
const regIpV6 = /^(([\da-fA-F]+)?:)+\/\d+/;
2020-02-19 15:55:06 +11:00
const internalIpRanges = {
2025-09-02 21:43:00 +10:00
interval_timeout: 1000 * 60 * 60 * 6, // 6 hours
interval: null,
2020-02-19 15:55:06 +11:00
interval_processing: false,
2025-09-02 21:43:00 +10:00
iteration_count: 0,
2020-02-19 15:55:06 +11:00
initTimer: () => {
2025-09-02 21:43:00 +10:00
logger.info("IP Ranges Renewal Timer initialized");
2020-02-19 15:55:06 +11:00
internalIpRanges.interval = setInterval(internalIpRanges.fetch, internalIpRanges.interval_timeout);
},
fetchUrl: (url) => {
const agent = new ProxyAgent();
2020-02-19 15:55:06 +11:00
return new Promise((resolve, reject) => {
2025-09-02 21:43:00 +10:00
logger.info(`Fetching ${url}`);
return https
.get(url, { agent }, (res) => {
2025-09-02 21:43:00 +10:00
res.setEncoding("utf8");
let raw_data = "";
res.on("data", (chunk) => {
raw_data += chunk;
});
2020-02-19 15:55:06 +11:00
2025-09-02 21:43:00 +10:00
res.on("end", () => {
resolve(raw_data);
});
})
.on("error", (err) => {
reject(err);
2020-02-19 15:55:06 +11:00
});
});
},
/**
* Triggered at startup and then later by a timer, this will fetch the ip ranges from services and apply them to nginx.
*/
fetch: () => {
if (!internalIpRanges.interval_processing) {
internalIpRanges.interval_processing = true;
2025-09-02 21:43:00 +10:00
logger.info("Fetching IP Ranges from online services...");
2020-02-19 15:55:06 +11:00
let ip_ranges = [];
2025-09-02 21:43:00 +10:00
return internalIpRanges
.fetchUrl(CLOUDFRONT_URL)
2020-02-19 15:55:06 +11:00
.then((cloudfront_data) => {
2025-09-02 21:43:00 +10:00
const data = JSON.parse(cloudfront_data);
2020-02-19 15:55:06 +11:00
2025-09-02 21:43:00 +10:00
if (data && typeof data.prefixes !== "undefined") {
2020-02-19 15:55:06 +11:00
data.prefixes.map((item) => {
2025-09-02 21:43:00 +10:00
if (item.service === "CLOUDFRONT") {
2020-02-19 15:55:06 +11:00
ip_ranges.push(item.ip_prefix);
}
2025-09-02 21:43:00 +10:00
return true;
2020-02-19 15:55:06 +11:00
});
}
2025-09-02 21:43:00 +10:00
if (data && typeof data.ipv6_prefixes !== "undefined") {
2020-02-19 15:55:06 +11:00
data.ipv6_prefixes.map((item) => {
2025-09-02 21:43:00 +10:00
if (item.service === "CLOUDFRONT") {
2020-02-19 15:55:06 +11:00
ip_ranges.push(item.ipv6_prefix);
}
2025-09-02 21:43:00 +10:00
return true;
2020-02-19 15:55:06 +11:00
});
}
})
.then(() => {
return internalIpRanges.fetchUrl(CLOUDFARE_V4_URL);
})
.then((cloudfare_data) => {
2025-09-02 21:43:00 +10:00
const items = cloudfare_data.split("\n").filter((line) => regIpV4.test(line));
ip_ranges = [...ip_ranges, ...items];
2020-02-19 15:55:06 +11:00
})
.then(() => {
return internalIpRanges.fetchUrl(CLOUDFARE_V6_URL);
})
.then((cloudfare_data) => {
2025-09-02 21:43:00 +10:00
const items = cloudfare_data.split("\n").filter((line) => regIpV6.test(line));
ip_ranges = [...ip_ranges, ...items];
2020-02-19 15:55:06 +11:00
})
.then(() => {
2025-09-02 21:43:00 +10:00
const clean_ip_ranges = [];
2020-02-19 15:55:06 +11:00
ip_ranges.map((range) => {
if (range) {
clean_ip_ranges.push(range);
}
2025-09-02 21:43:00 +10:00
return true;
2020-02-19 15:55:06 +11:00
});
2025-09-02 21:43:00 +10:00
return internalIpRanges.generateConfig(clean_ip_ranges).then(() => {
if (internalIpRanges.iteration_count) {
// Reload nginx
return internalNginx.reload();
}
});
2020-02-19 15:55:06 +11:00
})
.then(() => {
internalIpRanges.interval_processing = false;
internalIpRanges.iteration_count++;
})
.catch((err) => {
2025-09-02 21:43:00 +10:00
logger.fatal(err.message);
2020-02-19 15:55:06 +11:00
internalIpRanges.interval_processing = false;
});
}
},
/**
* @param {Array} ip_ranges
* @returns {Promise}
*/
generateConfig: (ip_ranges) => {
const renderEngine = utils.getRenderEngine();
2020-02-19 15:55:06 +11:00
return new Promise((resolve, reject) => {
let template = null;
2025-09-02 21:43:00 +10:00
const filename = "/etc/nginx/conf.d/include/ip_ranges.conf";
2020-02-19 15:55:06 +11:00
try {
2025-09-02 21:43:00 +10:00
template = fs.readFileSync(`${__dirname}/../templates/ip_ranges.conf`, { encoding: "utf8" });
2020-02-19 15:55:06 +11:00
} catch (err) {
2025-09-02 21:43:00 +10:00
reject(new errs.ConfigurationError(err.message));
2020-02-19 15:55:06 +11:00
return;
}
renderEngine
2025-09-02 21:43:00 +10:00
.parseAndRender(template, { ip_ranges: ip_ranges })
2020-02-19 15:55:06 +11:00
.then((config_text) => {
2025-09-02 21:43:00 +10:00
fs.writeFileSync(filename, config_text, { encoding: "utf8" });
2020-02-19 15:55:06 +11:00
resolve(true);
})
.catch((err) => {
2025-09-02 21:43:00 +10:00
logger.warn(`Could not write ${filename}: ${err.message}`);
reject(new errs.ConfigurationError(err.message));
2020-02-19 15:55:06 +11:00
});
});
2025-09-02 21:43:00 +10:00
},
2020-02-19 15:55:06 +11:00
};
2025-09-02 21:43:00 +10:00
export default internalIpRanges;