Add utility for converting CIDR ranges to IP ranges (#26904)

* Add utility for converting CIDR ranges to IP ranges

* Add CLI support for IP matcher ranges script

GitOrigin-RevId: 1432bf3efa269c0e8e9d58fce1575bb01d694b2f
This commit is contained in:
Antoine Clausse
2025-08-18 13:23:13 +02:00
committed by Copybot
parent ccd770f433
commit 0e6d5dc368
2 changed files with 99 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
#!/usr/bin/env node
// @ts-check
import minimist from 'minimist'
import { fileURLToPath } from 'node:url'
/**
* Converts an integer to its corresponding IPv4 address string representation
*
* @param {number} int
* @returns {string}
*/
const intToIp = int =>
[
(int >>> 24) & 0xff,
(int >>> 16) & 0xff,
(int >>> 8) & 0xff,
int & 0xff,
].join('.')
/**
* Convert CIDR to IP range
*
* @param {string} cidr
* @returns {{min: string, max: string}}
*/
const cidrToRange = cidr => {
const [ip, prefixLength] = cidr.split('/')
const prefix = parseInt(prefixLength)
// Convert IP to 32-bit integer
const ipParts = ip.split('.').map(part => parseInt(part))
const ipInt =
(ipParts[0] << 24) + (ipParts[1] << 16) + (ipParts[2] << 8) + ipParts[3]
// Calculate network mask
const mask = (0xffffffff << (32 - prefix)) >>> 0
// Calculate network and broadcast addresses
const network = (ipInt & mask) >>> 0
const broadcast = (network | (0xffffffff >>> prefix)) >>> 0
return {
min: intToIp(network),
max: intToIp(broadcast),
}
}
/**
* Converts an array of CIDR ranges into a single string representation.
* Each CIDR range is converted into its corresponding minimum and maximum IP range,
* formatted as "min..max". All resultant ranges are joined by a comma.
*
* @param {string[]} cidrRanges - An array of CIDR range strings to be converted.
* @returns {string} A string representation of the converted ranges where each
* range is formatted as "min..max" and joined by commas.
*/
export const convertCidrRanges = cidrRanges =>
cidrRanges
.map(cidr => {
const range = cidrToRange(cidr)
return `${range.min}..${range.max}`
})
.join(',')
// Only run CLI if this file is executed directly
if (fileURLToPath(import.meta.url) === process.argv[1]) {
const argv = minimist(process.argv.slice(2))
if (argv._.length === 0) {
console.log('Usage: node scripts/ip_matcher_ranges.mjs <cidr1> [cidr2] ...')
console.log(
'Example: node scripts/ip_matcher_ranges.mjs 192.168.1.0/24 10.0.0.0/8'
)
process.exit(1)
}
console.log(convertCidrRanges(argv._))
}

View File

@@ -0,0 +1,19 @@
import { convertCidrRanges } from '../../../../scripts/ip_matcher_ranges.mjs'
describe('IpMatcherRange', function () {
it('returns IP ranges from CIDR notation', function () {
const ranges = convertCidrRanges(['192.168.1.0/24'])
expect(ranges).to.deep.equal('192.168.1.0..192.168.1.255')
})
it('returns IP ranges from a variation CIDR notation', function () {
const ranges = convertCidrRanges([
'192.168.0.0/24',
'10.0.0.0/8',
'172.16.0.0/12',
])
expect(ranges).to.deep.equal(
'192.168.0.0..192.168.0.255,10.0.0.0..10.255.255.255,172.16.0.0..172.31.255.255'
)
})
})