Refactor ip range checks and support ipv6
This commit is contained in:
parent
c8ef1d6ccf
commit
287c2d1bbc
@ -18,6 +18,7 @@
|
||||
"dockerode": "^3.3.4",
|
||||
"follow-redirects": "^1.15.2",
|
||||
"i18next": "^21.9.2",
|
||||
"ipaddr.js": "^2.0.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"json-rpc-2.0": "^1.4.1",
|
||||
"memory-cache": "^0.2.0",
|
||||
|
||||
@ -25,6 +25,9 @@ dependencies:
|
||||
i18next:
|
||||
specifier: ^21.9.2
|
||||
version: 21.10.0
|
||||
ipaddr.js:
|
||||
specifier: ^2.0.1
|
||||
version: 2.0.1
|
||||
js-yaml:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
@ -1924,6 +1927,11 @@ packages:
|
||||
engines: {node: '>= 0.10'}
|
||||
dev: false
|
||||
|
||||
/ipaddr.js@2.0.1:
|
||||
resolution: {integrity: sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==}
|
||||
engines: {node: '>= 10'}
|
||||
dev: false
|
||||
|
||||
/is-arguments@1.1.1:
|
||||
resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
@ -2,51 +2,46 @@ import { getClientIp } from "@supercharge/request-ip";
|
||||
|
||||
import { getSettings } from "utils/config/config";
|
||||
|
||||
function checkIPRange(ip, ipSpace) {
|
||||
// Check if the given IP is in the ipSpace address space using
|
||||
// CIDR notation. If ipSpace is a plain IPv4 we just compare them.
|
||||
const ipSpaceParts = ipSpace.split("/");
|
||||
if (ipSpaceParts.length === 1) {
|
||||
if (ip === ipSpace) {
|
||||
return true;
|
||||
const ipaddr = require("ipaddr.js");
|
||||
|
||||
function checkSingleIPRange(ip, cidr) {
|
||||
try {
|
||||
const ipAddr = ipaddr.process(ip);
|
||||
// If the CIDR is not in the format of x.x.x.x/y, we assume it is a single IP
|
||||
if (!cidr.includes("/")) {
|
||||
const cidrIP = ipaddr.process(cidr);
|
||||
// If both are IPv6, we need to normalize the strings
|
||||
if (ipAddr.kind() === "ipv6" && cidrIP.kind() === "ipv6") {
|
||||
return (ipAddr.toNormalizedString() === cidrIP.toNormalizedString());
|
||||
}
|
||||
} else if (ipSpaceParts.length === 2) {
|
||||
const ipParts = ip.split(".");
|
||||
const ipNum = parseInt(ipParts[0], 10) * 256 * 256 * 256 + parseInt(ipParts[1], 10) * 256 * 256 + parseInt(ipParts[2], 10) * 256 + parseInt(ipParts[3], 10);
|
||||
const ipSpaceNum = parseInt(ipSpaceParts[0].split(".")[0], 10) * 256 * 256 * 256 + parseInt(ipSpaceParts[0].split(".")[1], 10) * 256 * 256 + parseInt(ipSpaceParts[0].split(".")[2], 10) * 256 + parseInt(ipSpaceParts[0].split(".")[3], 10);
|
||||
const mask = 32 - parseInt(ipSpaceParts[1], 10);
|
||||
// eslint-disable-next-line no-bitwise
|
||||
const maskNum = 0xffffffff << mask;
|
||||
// eslint-disable-next-line no-bitwise
|
||||
if ((ipNum & maskNum) === (ipSpaceNum & maskNum)) {
|
||||
return true;
|
||||
return ipAddr.toString() === cidrIP.toString();
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Invalid ipSpace: ${ipSpace}`);
|
||||
// Otherwise, we assume it is a CIDR range
|
||||
const range = ipaddr.parseCIDR(cidr);
|
||||
return ipAddr.match(range);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function checkIPRange(ip, range) {
|
||||
if (typeof range === "string") {
|
||||
return checkSingleIPRange(ip, range);
|
||||
}
|
||||
if (Array.isArray(range)) {
|
||||
return range.find((cidr) => checkSingleIPRange(ip, cidr)) !== undefined;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isRequestProxied(remoteAddress) {
|
||||
export function isRequestProxied(remoteAddress) {
|
||||
const settings = getSettings();
|
||||
// Check if trustedproxies is set
|
||||
const trustedProxies = settings?.trustedproxies;
|
||||
|
||||
// If trustedproxies is set, check if the client IP
|
||||
// is in the trustedproxies address space using CIDR notation.
|
||||
if (trustedProxies) {
|
||||
// Get the connection IP and strip IPv6 from the hybrid IPv4-IPv6 socket
|
||||
const ip = remoteAddress.replace(/^.*:/, '');
|
||||
|
||||
for (let i = 0; i < trustedProxies.length; i += 1) {
|
||||
const proxy = trustedProxies[i].trim();
|
||||
const inRange = checkIPRange(ip, proxy);
|
||||
if (inRange) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
// is in the trustedproxies address space.
|
||||
return trustedProxies ? checkIPRange(remoteAddress, trustedProxies) : false;
|
||||
}
|
||||
|
||||
export function getRealClientIP(req) {
|
||||
@ -63,17 +58,10 @@ export function isInLocalScope(req) {
|
||||
const localScope = settings?.localscope;
|
||||
|
||||
// If localscope is set, check if the client IP
|
||||
// is in the localscope address space using CIDR notation.
|
||||
// is in the localscope address space.
|
||||
if (localScope) {
|
||||
const ip = getRealClientIP(req);
|
||||
|
||||
for (let i = 0; i < localScope.length; i += 1) {
|
||||
const localIP = localScope[i].trim();
|
||||
const inRange = checkIPRange(ip, localIP)
|
||||
if (inRange) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return checkIPRange(ip, localScope);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user