mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-10-31 15:53:33 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			157 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import fs from "node:fs";
 | |
| import https from "node:https";
 | |
| import { dirname } from "node:path";
 | |
| import { fileURLToPath } from "node:url";
 | |
| 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";
 | |
| 
 | |
| const regIpV4 = /^(\d+\.?){4}\/\d+/;
 | |
| const regIpV6 = /^(([\da-fA-F]+)?:)+\/\d+/;
 | |
| 
 | |
| const internalIpRanges = {
 | |
| 	interval_timeout: 1000 * 60 * 60 * 6, // 6 hours
 | |
| 	interval: null,
 | |
| 	interval_processing: false,
 | |
| 	iteration_count: 0,
 | |
| 
 | |
| 	initTimer: () => {
 | |
| 		logger.info("IP Ranges Renewal Timer initialized");
 | |
| 		internalIpRanges.interval = setInterval(internalIpRanges.fetch, internalIpRanges.interval_timeout);
 | |
| 	},
 | |
| 
 | |
| 	fetchUrl: (url) => {
 | |
| 		return new Promise((resolve, reject) => {
 | |
| 			logger.info(`Fetching ${url}`);
 | |
| 			return https
 | |
| 				.get(url, (res) => {
 | |
| 					res.setEncoding("utf8");
 | |
| 					let raw_data = "";
 | |
| 					res.on("data", (chunk) => {
 | |
| 						raw_data += chunk;
 | |
| 					});
 | |
| 
 | |
| 					res.on("end", () => {
 | |
| 						resolve(raw_data);
 | |
| 					});
 | |
| 				})
 | |
| 				.on("error", (err) => {
 | |
| 					reject(err);
 | |
| 				});
 | |
| 		});
 | |
| 	},
 | |
| 
 | |
| 	/**
 | |
| 	 * 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;
 | |
| 			logger.info("Fetching IP Ranges from online services...");
 | |
| 
 | |
| 			let ip_ranges = [];
 | |
| 
 | |
| 			return internalIpRanges
 | |
| 				.fetchUrl(CLOUDFRONT_URL)
 | |
| 				.then((cloudfront_data) => {
 | |
| 					const data = JSON.parse(cloudfront_data);
 | |
| 
 | |
| 					if (data && typeof data.prefixes !== "undefined") {
 | |
| 						data.prefixes.map((item) => {
 | |
| 							if (item.service === "CLOUDFRONT") {
 | |
| 								ip_ranges.push(item.ip_prefix);
 | |
| 							}
 | |
| 							return true;
 | |
| 						});
 | |
| 					}
 | |
| 
 | |
| 					if (data && typeof data.ipv6_prefixes !== "undefined") {
 | |
| 						data.ipv6_prefixes.map((item) => {
 | |
| 							if (item.service === "CLOUDFRONT") {
 | |
| 								ip_ranges.push(item.ipv6_prefix);
 | |
| 							}
 | |
| 							return true;
 | |
| 						});
 | |
| 					}
 | |
| 				})
 | |
| 				.then(() => {
 | |
| 					return internalIpRanges.fetchUrl(CLOUDFARE_V4_URL);
 | |
| 				})
 | |
| 				.then((cloudfare_data) => {
 | |
| 					const items = cloudfare_data.split("\n").filter((line) => regIpV4.test(line));
 | |
| 					ip_ranges = [...ip_ranges, ...items];
 | |
| 				})
 | |
| 				.then(() => {
 | |
| 					return internalIpRanges.fetchUrl(CLOUDFARE_V6_URL);
 | |
| 				})
 | |
| 				.then((cloudfare_data) => {
 | |
| 					const items = cloudfare_data.split("\n").filter((line) => regIpV6.test(line));
 | |
| 					ip_ranges = [...ip_ranges, ...items];
 | |
| 				})
 | |
| 				.then(() => {
 | |
| 					const clean_ip_ranges = [];
 | |
| 					ip_ranges.map((range) => {
 | |
| 						if (range) {
 | |
| 							clean_ip_ranges.push(range);
 | |
| 						}
 | |
| 						return true;
 | |
| 					});
 | |
| 
 | |
| 					return internalIpRanges.generateConfig(clean_ip_ranges).then(() => {
 | |
| 						if (internalIpRanges.iteration_count) {
 | |
| 							// Reload nginx
 | |
| 							return internalNginx.reload();
 | |
| 						}
 | |
| 					});
 | |
| 				})
 | |
| 				.then(() => {
 | |
| 					internalIpRanges.interval_processing = false;
 | |
| 					internalIpRanges.iteration_count++;
 | |
| 				})
 | |
| 				.catch((err) => {
 | |
| 					logger.fatal(err.message);
 | |
| 					internalIpRanges.interval_processing = false;
 | |
| 				});
 | |
| 		}
 | |
| 	},
 | |
| 
 | |
| 	/**
 | |
| 	 * @param   {Array}  ip_ranges
 | |
| 	 * @returns {Promise}
 | |
| 	 */
 | |
| 	generateConfig: (ip_ranges) => {
 | |
| 		const renderEngine = utils.getRenderEngine();
 | |
| 		return new Promise((resolve, reject) => {
 | |
| 			let template = null;
 | |
| 			const filename = "/etc/nginx/conf.d/include/ip_ranges.conf";
 | |
| 			try {
 | |
| 				template = fs.readFileSync(`${__dirname}/../templates/ip_ranges.conf`, { encoding: "utf8" });
 | |
| 			} catch (err) {
 | |
| 				reject(new errs.ConfigurationError(err.message));
 | |
| 				return;
 | |
| 			}
 | |
| 
 | |
| 			renderEngine
 | |
| 				.parseAndRender(template, { ip_ranges: ip_ranges })
 | |
| 				.then((config_text) => {
 | |
| 					fs.writeFileSync(filename, config_text, { encoding: "utf8" });
 | |
| 					resolve(true);
 | |
| 				})
 | |
| 				.catch((err) => {
 | |
| 					logger.warn(`Could not write ${filename}: ${err.message}`);
 | |
| 					reject(new errs.ConfigurationError(err.message));
 | |
| 				});
 | |
| 		});
 | |
| 	},
 | |
| };
 | |
| 
 | |
| export default internalIpRanges;
 |