function ipStringToNumber(str) { var arr = str.split("."); if(arr.length != 4) { return null; } var hexString = ""; for(var i = 0; i < arr.length; i++) { var byte = Number(arr[i]); if(byte == NaN || byte < 0 || byte > 255) { return null; } byteHex = byte.toString(16); if(byteHex.length == 1) { byteHex = "0"+byteHex; } hexString += byteHex; } //console.log(hexString); return parseInt(hexString, 16); } function toIpString(ipNumber) { var hexString = ipNumber.toString(16); while(hexString.length < 8) { hexString = "0"+hexString; } //console.log("ipNumber: "+ ipNumber + ", hexString: " + hexString); return parseInt(""+hexString[0]+hexString[1], 16)+"."+parseInt(""+hexString[2]+hexString[3], 16)+"."+parseInt(""+hexString[4]+hexString[5], 16)+"."+parseInt(""+hexString[6]+hexString[7], 16); } function parseCidr(cidrString) { var arr = cidrString.split("/"); if(arr.length != 2) { console.log("invalid cidr format: " + cidrString ); return; } var ipNumber = ipStringToNumber(arr[0]); var sizeBits = Number(arr[1]); if(ipNumber === null) { console.log("invalid cidr IP: " + arr[0] ); return; } if(sizeBits < 0 || sizeBits > 32) { console.log("invalid cidr sizeBits: " + arr[1]); return; } var blockSize = (1 << (32-sizeBits)); if(ipNumber % blockSize != 0) { ipNumber -= (ipNumber % blockSize); console.log("warning: cidr start IP was not aligned with mask. assuming: " + toIpString(ipNumber)+"/"+sizeBits); } return {ipNumber: ipNumber, sizeBits:sizeBits}; } function cidrObjectToString(cidrObject) { return toIpString(cidrObject.ipNumber)+"/"+cidrObject.sizeBits; } function cidrSubtract(cidrToSubtractFrom, cidrToSubtract) { if(typeof cidrToSubtractFrom == "string") { cidrToSubtractFrom = parseCidr(cidrToSubtractFrom) } if(typeof cidrToSubtract == "string") { cidrToSubtract = parseCidr(cidrToSubtract) } console.log("cidrToSubtractFrom: " + JSON.stringify(cidrToSubtractFrom, null, 2) + ", cidrToSubtract: " + JSON.stringify(cidrToSubtract, null, 2) ); var currentIp = cidrToSubtractFrom.ipNumber; var currentSizeBits = cidrToSubtractFrom.sizeBits; var results = []; var itr = 0; while(itr++ < 32) { currentSizeBits += 1; newBlockSize = Math.pow(2, 32-currentSizeBits); isAlignedBlock = (currentIp % newBlockSize == 0); isSmallEnough = (currentIp + (newBlockSize-1) < cidrToSubtract.ipNumber ); fits = (currentIp + newBlockSize === cidrToSubtract.ipNumber); //console.log("currentIp: " +currentIp+", (newBlockSize-1): "+ (newBlockSize-1) + ", (newBlockSize): "+ (newBlockSize)); //console.log("currentIp + (newBlockSize-1): "+ (currentIp + (newBlockSize-1)) + " (" + toIpString(currentIp + (newBlockSize-1)) + "), cidrToSubtract.ipNumber: " + cidrToSubtract.ipNumber + " ("+ toIpString(cidrToSubtract.ipNumber) + ")"); //console.log(toIpString(currentIp)+"/"+currentSizeBits + ": isSmallEnough: " + isSmallEnough + " isAlignedBlock: " + isAlignedBlock + " fits: " + fits ); if(isAlignedBlock && isSmallEnough) { results.push(cidrObjectToString({ipNumber: currentIp, sizeBits:currentSizeBits})); currentIp += newBlockSize; } if(fits) { break; } } results.push("-------------"); var results2 = []; currentSizeBits = cidrToSubtractFrom.sizeBits; var blockSize = Math.pow(2, 32-currentSizeBits); currentIp = cidrToSubtractFrom.ipNumber+blockSize; var endOfCidrToSubtract = cidrToSubtract.ipNumber+Math.pow(2, 32-cidrToSubtract.sizeBits); var itr = 0; while(itr++ < 32) { currentSizeBits += 1; newBlockSize = Math.pow(2, 32-currentSizeBits); isAlignedBlock = (currentIp % newBlockSize == 0); isSmallEnough = (currentIp - (newBlockSize-1) > endOfCidrToSubtract ); fits = (currentIp - newBlockSize === endOfCidrToSubtract); //console.log("currentIp: " +currentIp+", (newBlockSize-1): "+ (newBlockSize-1) + ", (newBlockSize): "+ (newBlockSize)); //console.log("currentIp - newBlockSize: (" + toIpString(currentIp - newBlockSize) + "), endOfCidrToSubtract: ("+ toIpString(endOfCidrToSubtract) + ")"); //console.log(toIpString(currentIp)+"/"+currentSizeBits + ": isSmallEnough: " + isSmallEnough + " isAlignedBlock: " + isAlignedBlock + " fits: " + fits ); if(isAlignedBlock && isSmallEnough) { results2.unshift(cidrObjectToString({ipNumber: currentIp - newBlockSize, sizeBits:currentSizeBits})); currentIp -= newBlockSize; } if(fits) { break; } } console.log(results.concat(results2).join("\n")); } cidrSubtract("0.0.0.0/0", "172.23.0.0/22")