diff --git a/src/core/lib/IP.mjs b/src/core/lib/IP.mjs
index c97f87ab..02d46d42 100644
--- a/src/core/lib/IP.mjs
+++ b/src/core/lib/IP.mjs
@@ -25,7 +25,7 @@ export function ipv4CidrRange(cidr, includeNetworkInfo, enumerateAddresses, allo
cidrRange = parseInt(cidr[2], 10);
let output = "";
- if (cidrRange < 0 || cidrRange > 31) {
+ if (!validateCidr(cidrRange)) {
throw new OperationError("IPv4 CIDR must be less than 32");
}
@@ -189,6 +189,57 @@ export function ipv6HyphenatedRange(range, includeNetworkInfo) {
return output;
}
+/**
+ * Parses an IPv4 subnet mask (e.g. 192.168.0.0/255.255.255.0) and displays information about it.
+ *
+ * @param {RegExp} match
+ * @param {boolean} includeNetworkInfo
+ * @param {boolean} enumerateAddresses
+ * @param {boolean} allowLargeList
+ * @returns {string}
+ */
+export function ipv4SubnetMask(match, includeNetworkInfo, enumerateAddresses, allowLargeList) {
+ const network = strToIpv4(match[1]),
+ mask = strToIpv4(match[2]);
+ let output = "",
+ maskCalculate = mask,
+ cidr = 0;
+
+ // Validate the subnet mask
+ if (!validateSubnetMask(mask)) {
+ throw new OperationError("Invalid subnet mask");
+ }
+
+ // Calculate the CIDR
+ while (maskCalculate) {
+ cidr += maskCalculate & 1;
+ maskCalculate >>>= 1;
+ }
+ if (!validateCidr(cidr)) {
+ throw new OperationError("IPv4 CIDR must be less than 32");
+ }
+
+ const ip1 = network & mask,
+ ip2 = ip1 | ~mask;
+
+ if (includeNetworkInfo) {
+ output += "Network: " + ipv4ToStr(network) + "\n";
+ output += "CIDR: " + cidr + "\n";
+ output += "Mask: " + ipv4ToStr(mask) + "\n";
+ output += "Range: " + ipv4ToStr(ip1) + " - " + ipv4ToStr(ip2) + "\n";
+ output += "Total addresses in range: " + (((ip2 - ip1) >>> 0) + 1) + "\n\n";
+ }
+
+ if (enumerateAddresses) {
+ if (cidr >= 16 || allowLargeList) {
+ output += generateIpv4Range(ip1, ip2).join("\n");
+ } else {
+ output += _LARGE_RANGE_ERROR;
+ }
+ }
+ return output;
+}
+
/**
* Parses a list of IPv4 addresses separated by a new line (\n) and displays information
* about it.
@@ -207,15 +258,27 @@ export function ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, a
const ipv4CidrList = ipv4List.filter(function(a) {
return a.includes("/");
});
+ const cidrCheck = /^\d\d?$/;
for (let i = 0; i < ipv4CidrList.length; i++) {
const network = strToIpv4(ipv4CidrList[i].split("/")[0]);
- const cidrRange = parseInt(ipv4CidrList[i].split("/")[1], 10);
- if (cidrRange < 0 || cidrRange > 31) {
- throw new OperationError("IPv4 CIDR must be less than 32");
+ const cidr = ipv4CidrList[i].split("/")[1];
+ let mask;
+
+ // Check if this is a CIDR or subnet mask
+ if (cidrCheck.exec(cidr)) {
+ const cidrRange = parseInt(cidr, 10);
+ if (!validateCidr(cidrRange)) {
+ throw new OperationError("IPv4 CIDR must be less than 32");
+ }
+ mask = ~(0xFFFFFFFF >>> cidrRange);
+ } else {
+ mask = strToIpv4(cidr);
+ if (!validateSubnetMask(mask)) {
+ throw new OperationError("Invalid subnet mask");
+ }
}
- const mask = ~(0xFFFFFFFF >>> cidrRange),
- cidrIp1 = network & mask,
- cidrIp2 = cidrIp1 | ~mask;
+ const cidrIp1 = network & mask;
+ const cidrIp2 = cidrIp1 | ~mask;
ipv4List.splice(ipv4List.indexOf(ipv4CidrList[i]), 1);
ipv4List.push(ipv4ToStr(cidrIp1), ipv4ToStr(cidrIp2));
}
@@ -509,6 +572,34 @@ export function ipv6Compare(a, b) {
}
return 0;
}
+/**
+ * Validates a given subnet mask
+ *
+ * @param {string} mask
+ * @returns {boolean}
+ */
+export function validateSubnetMask (mask) {
+ for (; mask !== 0; mask <<= 1) {
+ if ((mask & (1<<31)) === 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * Validates a given CIDR
+ *
+ * @param {string} cidr
+ * @returns {boolean}
+ */
+export function validateCidr (cidr) {
+ if (cidr < 0 || cidr > 31) {
+ return false;
+ } else {
+ return true;
+ }
+}
const _LARGE_RANGE_ERROR = "The specified range contains more than 65,536 addresses. Running this query could crash your browser. If you want to run it, select the \"Allow large queries\" option. You are advised to turn off \"Auto Bake\" whilst editing large ranges.";
diff --git a/src/core/operations/ParseIPRange.mjs b/src/core/operations/ParseIPRange.mjs
index 2c59c015..ec4a7fc8 100644
--- a/src/core/operations/ParseIPRange.mjs
+++ b/src/core/operations/ParseIPRange.mjs
@@ -7,7 +7,7 @@
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
-import {ipv4CidrRange, ipv4HyphenatedRange, ipv4ListedRange, ipv6CidrRange, ipv6HyphenatedRange, ipv6ListedRange} from "../lib/IP.mjs";
+import {ipv4CidrRange, ipv4HyphenatedRange, ipv4SubnetMask, ipv4ListedRange, ipv6CidrRange, ipv6HyphenatedRange, ipv6ListedRange} from "../lib/IP.mjs";
/**
* Parse IP range operation
@@ -22,7 +22,7 @@ class ParseIPRange extends Operation {
this.name = "Parse IP range";
this.module = "Default";
- this.description = "Given a CIDR range (e.g. 10.0.0.0/24
), hyphenated range (e.g. 10.0.0.0 - 10.0.1.0
), or a list of IPs and/or CIDR ranges (separated by a new line), this operation provides network information and enumerates all IP addresses in the range.
IPv6 is supported but will not be enumerated.";
+ this.description = "This operation provides network information and enumerates all IP addresses in the given range.
Supported inputs:
10.0.0.0/24
)10.0.0.0/255.255.255.0
)10.0.0.0 - 10.0.1.0
). Only one hyphenated range is allowed