Fix(ip): validate subnet split limits before conversion

Return null for invalid options or limits instead of throwing during
BigInt conversion. Preserve zero, default, and safe integer limits.

Co-Authored-By: GPT-6 <noreply@openai.com>
This commit is contained in:
jason5ng32andGPT-6 committed 2026-09-17 10:49:17 +08:00
1 parent 6de54d7e44
commit 0c6e5f2c7a
2 files changed
+27 -1

No files matched your search

+4 -1
View File
@@ -281,7 +281,10 @@ export const compareIps = (a, b) => {
// Children of `cidrStr` at `newPrefix`. `total` is exact; `subnets` stops at
// `limit` so a /8 → /32 request never materialises 16M strings.
export const splitCidr = (cidrStr, newPrefix, { limit = 1024 } = {}) => {
export const splitCidr = (cidrStr, newPrefix, options = {}) => {
if (!options || typeof options !== 'object' || Array.isArray(options)) return null;
const { limit = 1024 } = options;
if (!Number.isSafeInteger(limit) || limit < 0) return null;
const cidr = parseCidr(cidrStr);
if (!cidr || !isPrefix(newPrefix, cidr.family) || newPrefix < cidr.prefix) return null;
const { family, network } = cidr;
+23
View File
@@ -293,6 +293,29 @@ describe('containment & ordering', () => {
});
describe('splitCidr', () => {
it('rejects invalid limits and options without coercing them', () => {
const limits = [Infinity, -Infinity, NaN, 1.5, -1, Number.MAX_SAFE_INTEGER + 1,
Symbol('limit'), '4', 4n, null, true, {}, []];
for (const limit of limits) {
assert.equal(splitCidr('10.0.0.0/24', 26, { limit }), null);
assert.equal(splitCidr('2001:db8::/32', 48, { limit }), null);
}
for (const options of [null, false, 5, '4', 4n, Symbol('options'), []]) {
assert.equal(splitCidr('10.0.0.0/24', 26, options), null);
}
});
it('accepts zero, default and large safe limits without changing the exact total', () => {
const zero = splitCidr('10.0.0.0/24', 26, { limit: 0 });
assert.deepEqual(zero.subnets, []);
assert.equal(zero.total, 4n);
assert.equal(zero.truncated, true);
for (const limit of [undefined, 4, Number.MAX_SAFE_INTEGER]) {
const result = splitCidr('10.0.0.0/24', 26, { limit });
assert.equal(result.subnets.length, 4);
assert.equal(result.total, 4n);
assert.equal(result.truncated, false);
}
});
it('splits a /24 into /26s', () => {
const r = splitCidr('10.0.0.0/24', 26);
assert.deepEqual(r.subnets, ['10.0.0.0/26', '10.0.0.64/26', '10.0.0.128/26', '10.0.0.192/26']);