cidr-tools 12.1.1 → 12.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +67 -105
- package/package.json +15 -15
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ function parseIPv4Fast(s, end) {
|
|
|
38
38
|
if (dots !== 3 || digits === 0 || octet > 255) return -1;
|
|
39
39
|
return (num << 8 | octet) >>> 0;
|
|
40
40
|
}
|
|
41
|
+
const hostMasks4 = Int32Array.from({ length: 33 }, (_, i) => i === 32 ? -1 : (1 << i) - 1);
|
|
41
42
|
function formatIPv4Fast(n) {
|
|
42
43
|
return octetDotStrings[n >>> 24 & 255] + octetDotStrings[n >>> 16 & 255] + octetDotStrings[n >>> 8 & 255] + octetStrings[n & 255];
|
|
43
44
|
}
|
|
@@ -61,15 +62,9 @@ function parseIPv4Range(str) {
|
|
|
61
62
|
const v4num = parseIPv4Fast(str, rangeSlashIndex !== -1 ? rangeSlashIndex : str.length);
|
|
62
63
|
if (v4num === -1) return false;
|
|
63
64
|
rangeV4Prefix = rangeSlashIndex !== -1 ? parsePrefixNum(str, rangeSlashIndex) : 32;
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
rangeV4End = 4294967295;
|
|
68
|
-
} else {
|
|
69
|
-
const mask = hostBits > 0 ? (1 << hostBits >>> 0) - 1 : 0;
|
|
70
|
-
rangeV4Start = (v4num & ~mask) >>> 0;
|
|
71
|
-
rangeV4End = (v4num | mask) >>> 0;
|
|
72
|
-
}
|
|
65
|
+
const mask = hostMasks4[Math.max(32 - rangeV4Prefix, 0)];
|
|
66
|
+
rangeV4Start = (v4num & ~mask) >>> 0;
|
|
67
|
+
rangeV4End = (v4num | mask) >>> 0;
|
|
73
68
|
return true;
|
|
74
69
|
}
|
|
75
70
|
function doNormalize(cidr, opts) {
|
|
@@ -80,14 +75,12 @@ function doNormalize(cidr, opts) {
|
|
|
80
75
|
const slashIndex = rangeSlashIndex;
|
|
81
76
|
const prefixPresent = slashIndex !== -1;
|
|
82
77
|
let prefixNum = prefixPresent ? parsePrefixNum(cidr, slashIndex) : -1;
|
|
83
|
-
const { number, version } = parseIp(prefixPresent ? cidr.substring(0, slashIndex) : cidr);
|
|
78
|
+
const { number, version, ipv4mapped, scopeid } = parseIp(prefixPresent ? cidr.substring(0, slashIndex) : cidr);
|
|
84
79
|
if (prefixNum === -1) prefixNum = bits[version];
|
|
85
80
|
if (version === 4) {
|
|
86
81
|
const hostBits = 32 - prefixNum;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
else if (hostBits > 0) startNum = (startNum & ~((1 << hostBits >>> 0) - 1)) >>> 0;
|
|
90
|
-
const ip = formatIPv4Fast(startNum);
|
|
82
|
+
const mask = hostMasks4[Math.max(hostBits, 0)];
|
|
83
|
+
const ip = formatIPv4Fast((Number(number) & ~mask) >>> 0);
|
|
91
84
|
return hostBits > 0 || prefixPresent ? ip + prefixStrings[prefixNum] : ip;
|
|
92
85
|
}
|
|
93
86
|
const { compress = true, hexify = false } = opts || {};
|
|
@@ -96,10 +89,13 @@ function doNormalize(cidr, opts) {
|
|
|
96
89
|
compress,
|
|
97
90
|
hexify
|
|
98
91
|
});
|
|
92
|
+
const start = hostBits > 0 ? number & hostNotMasks[hostBits] : number;
|
|
99
93
|
const ip = stringifyIp({
|
|
100
|
-
number:
|
|
101
|
-
version
|
|
102
|
-
|
|
94
|
+
number: start,
|
|
95
|
+
version,
|
|
96
|
+
ipv4mapped: ipv4mapped && start >> 32n === 65535n,
|
|
97
|
+
scopeid
|
|
98
|
+
}, { hexify });
|
|
103
99
|
return (compress ? ip : normalizeIp(ip, {
|
|
104
100
|
compress,
|
|
105
101
|
hexify
|
|
@@ -119,24 +115,15 @@ function parseCidr(str) {
|
|
|
119
115
|
const prefixNum = prefixPresent ? parsePrefixNum(str, slashIndex) : 32;
|
|
120
116
|
const ip = formatIPv4Fast(v4num);
|
|
121
117
|
const prefix = prefixNumStrings[prefixNum] ?? String(prefixNum);
|
|
122
|
-
const
|
|
123
|
-
let startNum, endNum;
|
|
124
|
-
if (hostBits >= 32) {
|
|
125
|
-
startNum = 0;
|
|
126
|
-
endNum = 4294967295;
|
|
127
|
-
} else {
|
|
128
|
-
const mask = hostBits > 0 ? (1 << hostBits >>> 0) - 1 : 0;
|
|
129
|
-
startNum = (v4num & ~mask) >>> 0;
|
|
130
|
-
endNum = (v4num | mask) >>> 0;
|
|
131
|
-
}
|
|
118
|
+
const mask = hostMasks4[Math.max(32 - prefixNum, 0)];
|
|
132
119
|
return {
|
|
133
120
|
cidr: ip + prefixStrings[prefixNum],
|
|
134
121
|
ip,
|
|
135
122
|
version: 4,
|
|
136
123
|
prefix,
|
|
137
124
|
prefixPresent,
|
|
138
|
-
start: BigInt(
|
|
139
|
-
end: BigInt(
|
|
125
|
+
start: BigInt((v4num & ~mask) >>> 0),
|
|
126
|
+
end: BigInt((v4num | mask) >>> 0)
|
|
140
127
|
};
|
|
141
128
|
}
|
|
142
129
|
const ipPart = prefixPresent ? str.substring(0, slashIndex) : str;
|
|
@@ -185,12 +172,7 @@ function parseCidrLean(str) {
|
|
|
185
172
|
const hostBits = numBits - prefixNum;
|
|
186
173
|
if (version === 4) {
|
|
187
174
|
const num = Number(number);
|
|
188
|
-
|
|
189
|
-
start: 0,
|
|
190
|
-
end: 4294967295,
|
|
191
|
-
version: 4
|
|
192
|
-
};
|
|
193
|
-
const mask = hostBits > 0 ? (1 << hostBits >>> 0) - 1 : 0;
|
|
175
|
+
const mask = hostMasks4[Math.max(hostBits, 0)];
|
|
194
176
|
return {
|
|
195
177
|
start: (num & ~mask) >>> 0,
|
|
196
178
|
end: (num | mask) >>> 0,
|
|
@@ -364,13 +346,11 @@ function subtractSorted6(bases, excls) {
|
|
|
364
346
|
}
|
|
365
347
|
/** Returns an array of merged networks */
|
|
366
348
|
function mergeCidr(nets) {
|
|
367
|
-
const
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
if (n.version === 4) v4.push(n);
|
|
373
|
-
else v6.push(n);
|
|
349
|
+
const v4 = [], v6 = [];
|
|
350
|
+
for (const str of typeof nets === "string" ? [nets] : nets) {
|
|
351
|
+
const net = parseCidrLean(str);
|
|
352
|
+
if (net.version === 4) v4.push(net);
|
|
353
|
+
else v6.push(net);
|
|
374
354
|
}
|
|
375
355
|
const merged = [];
|
|
376
356
|
for (const part of mergeIntervalsRaw4(v4)) subparts4(part.start, part.end, merged);
|
|
@@ -379,42 +359,30 @@ function mergeCidr(nets) {
|
|
|
379
359
|
}
|
|
380
360
|
/** Returns an array of merged remaining networks of the subtraction of `excludeNetworks` from `baseNetworks`. */
|
|
381
361
|
function excludeCidr(base, excl) {
|
|
382
|
-
const baseArr = typeof base === "string" ? [base] : base;
|
|
383
|
-
const exclArr = typeof excl === "string" ? [excl] : excl;
|
|
384
362
|
const v4base = [], v6base = [];
|
|
385
363
|
const v4excl = [], v6excl = [];
|
|
386
|
-
for (const
|
|
387
|
-
const
|
|
388
|
-
if (
|
|
389
|
-
else v6base.push(
|
|
364
|
+
for (const str of typeof base === "string" ? [base] : base) {
|
|
365
|
+
const net = parseCidrLean(str);
|
|
366
|
+
if (net.version === 4) v4base.push(net);
|
|
367
|
+
else v6base.push(net);
|
|
390
368
|
}
|
|
391
|
-
for (const
|
|
392
|
-
const
|
|
393
|
-
if (
|
|
394
|
-
else v6excl.push(
|
|
369
|
+
for (const str of typeof excl === "string" ? [excl] : excl) {
|
|
370
|
+
const net = parseCidrLean(str);
|
|
371
|
+
if (net.version === 4) v4excl.push(net);
|
|
372
|
+
else v6excl.push(net);
|
|
395
373
|
}
|
|
396
374
|
const result = [];
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
const exclParts = mergeIntervalsRaw4(v4excl);
|
|
400
|
-
for (const part of subtractSorted4(baseParts, exclParts)) subparts4(part.start, part.end, result);
|
|
401
|
-
}
|
|
402
|
-
{
|
|
403
|
-
const baseParts = mergeIntervalsRaw6(v6base);
|
|
404
|
-
const exclParts = mergeIntervalsRaw6(v6excl);
|
|
405
|
-
for (const part of subtractSorted6(baseParts, exclParts)) subparts6(part.start, part.end, result);
|
|
406
|
-
}
|
|
375
|
+
if (v4base.length > 0) for (const part of subtractSorted4(mergeIntervalsRaw4(v4base), mergeIntervalsRaw4(v4excl))) subparts4(part.start, part.end, result);
|
|
376
|
+
if (v6base.length > 0) for (const part of subtractSorted6(mergeIntervalsRaw6(v6base), mergeIntervalsRaw6(v6excl))) subparts6(part.start, part.end, result);
|
|
407
377
|
return result;
|
|
408
378
|
}
|
|
409
379
|
/** Returns a generator for individual IPs contained in the networks. */
|
|
410
380
|
function* expandCidr(nets) {
|
|
411
|
-
const
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
if (n.version === 4) v4.push(n);
|
|
417
|
-
else v6.push(n);
|
|
381
|
+
const v4 = [], v6 = [];
|
|
382
|
+
for (const str of typeof nets === "string" ? [nets] : nets) {
|
|
383
|
+
const net = parseCidrLean(str);
|
|
384
|
+
if (net.version === 4) v4.push(net);
|
|
385
|
+
else v6.push(net);
|
|
418
386
|
}
|
|
419
387
|
if (v4.length > 0) for (const part of mergeIntervalsRaw4(v4)) {
|
|
420
388
|
let prevHigh = -1;
|
|
@@ -470,26 +438,22 @@ function overlapCidr(a, b) {
|
|
|
470
438
|
if (pa.version !== pb.version) return false;
|
|
471
439
|
return pa.start <= pb.end && pb.start <= pa.end;
|
|
472
440
|
}
|
|
473
|
-
const aArr = typeof a === "string" ? [a] : a;
|
|
474
|
-
const bArr = typeof b === "string" ? [b] : b;
|
|
475
441
|
const v4a = [], v6a = [];
|
|
476
442
|
const v4b = [], v6b = [];
|
|
477
|
-
for (const
|
|
478
|
-
const
|
|
479
|
-
if (
|
|
480
|
-
else v6a.push(
|
|
481
|
-
}
|
|
482
|
-
for (const
|
|
483
|
-
const
|
|
484
|
-
if (
|
|
485
|
-
else v6b.push(
|
|
486
|
-
}
|
|
487
|
-
if (v4a.length > 0 && v4b.length > 0) if (v4b.length === 1) {
|
|
488
|
-
const
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const as = v4a[0].start, ae = v4a[0].end;
|
|
492
|
-
for (const el of v4b) if (as <= el.end && el.start <= ae) return true;
|
|
443
|
+
for (const str of typeof a === "string" ? [a] : a) {
|
|
444
|
+
const net = parseCidrLean(str);
|
|
445
|
+
if (net.version === 4) v4a.push(net);
|
|
446
|
+
else v6a.push(net);
|
|
447
|
+
}
|
|
448
|
+
for (const str of typeof b === "string" ? [b] : b) {
|
|
449
|
+
const net = parseCidrLean(str);
|
|
450
|
+
if (net.version === 4) v4b.push(net);
|
|
451
|
+
else v6b.push(net);
|
|
452
|
+
}
|
|
453
|
+
if (v4a.length > 0 && v4b.length > 0) if (v4a.length === 1 || v4b.length === 1) {
|
|
454
|
+
const bIsSingle = v4b.length === 1;
|
|
455
|
+
const one = bIsSingle ? v4b[0] : v4a[0];
|
|
456
|
+
for (const el of bIsSingle ? v4a : v4b) if (one.start <= el.end && el.start <= one.end) return true;
|
|
493
457
|
} else {
|
|
494
458
|
v4a.sort(cmpV4Start);
|
|
495
459
|
v4b.sort(cmpV4Start);
|
|
@@ -500,12 +464,10 @@ function overlapCidr(a, b) {
|
|
|
500
464
|
else j++;
|
|
501
465
|
}
|
|
502
466
|
}
|
|
503
|
-
if (v6a.length > 0 && v6b.length > 0) if (v6b.length === 1) {
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const as = v6a[0].start, ae = v6a[0].end;
|
|
508
|
-
for (const el of v6b) if (as <= el.end && el.start <= ae) return true;
|
|
467
|
+
if (v6a.length > 0 && v6b.length > 0) if (v6a.length === 1 || v6b.length === 1) {
|
|
468
|
+
const bIsSingle = v6b.length === 1;
|
|
469
|
+
const one = bIsSingle ? v6b[0] : v6a[0];
|
|
470
|
+
for (const el of bIsSingle ? v6a : v6b) if (one.start <= el.end && el.start <= one.end) return true;
|
|
509
471
|
} else {
|
|
510
472
|
v6a.sort(cmpV6Start);
|
|
511
473
|
v6b.sort(cmpV6Start);
|
|
@@ -533,19 +495,17 @@ function containsCidr(a, b) {
|
|
|
533
495
|
if (pa.version !== pb.version) return false;
|
|
534
496
|
return pa.start <= pb.start && pa.end >= pb.end;
|
|
535
497
|
}
|
|
536
|
-
const aArr = typeof a === "string" ? [a] : a;
|
|
537
|
-
const bArr = typeof b === "string" ? [b] : b;
|
|
538
498
|
const v4a = [], v6a = [];
|
|
539
499
|
const v4b = [], v6b = [];
|
|
540
|
-
for (const
|
|
541
|
-
const
|
|
542
|
-
if (
|
|
543
|
-
else v6a.push(
|
|
500
|
+
for (const str of typeof a === "string" ? [a] : a) {
|
|
501
|
+
const net = parseCidrLean(str);
|
|
502
|
+
if (net.version === 4) v4a.push(net);
|
|
503
|
+
else v6a.push(net);
|
|
544
504
|
}
|
|
545
|
-
for (const
|
|
546
|
-
const
|
|
547
|
-
if (
|
|
548
|
-
else v6b.push(
|
|
505
|
+
for (const str of typeof b === "string" ? [b] : b) {
|
|
506
|
+
const net = parseCidrLean(str);
|
|
507
|
+
if (net.version === 4) v4b.push(net);
|
|
508
|
+
else v6b.push(net);
|
|
549
509
|
}
|
|
550
510
|
if (v4b.length > 0) {
|
|
551
511
|
if (v4a.length === 0) return false;
|
|
@@ -553,7 +513,8 @@ function containsCidr(a, b) {
|
|
|
553
513
|
for (const target of v4b) {
|
|
554
514
|
const ts = target.start, te = target.end;
|
|
555
515
|
let covered = false;
|
|
556
|
-
for (const iv of v4a)
|
|
516
|
+
for (const iv of v4a) {
|
|
517
|
+
if (iv.start > ts || iv.end < te) continue;
|
|
557
518
|
covered = true;
|
|
558
519
|
break;
|
|
559
520
|
}
|
|
@@ -582,7 +543,8 @@ function containsCidr(a, b) {
|
|
|
582
543
|
for (const target of v6b) {
|
|
583
544
|
const ts = target.start, te = target.end;
|
|
584
545
|
let covered = false;
|
|
585
|
-
for (const iv of v6a)
|
|
546
|
+
for (const iv of v6a) {
|
|
547
|
+
if (iv.start > ts || iv.end < te) continue;
|
|
586
548
|
covered = true;
|
|
587
549
|
break;
|
|
588
550
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cidr-tools",
|
|
3
|
-
"version": "12.1.
|
|
3
|
+
"version": "12.1.3",
|
|
4
4
|
"author": "silverwind <me@silverwind.io>",
|
|
5
5
|
"description": "Tools to work with IPv4 and IPv6 CIDR",
|
|
6
6
|
"keywords": [
|
|
@@ -29,23 +29,23 @@
|
|
|
29
29
|
"bun": "*"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"ip-bigint": "^9.0.
|
|
32
|
+
"ip-bigint": "^9.0.7"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@types/node": "
|
|
36
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
37
|
-
"@vitest/coverage-v8": "4.1.
|
|
38
|
-
"eslint": "10.
|
|
39
|
-
"eslint-config-silverwind": "
|
|
35
|
+
"@types/node": "26.1.2",
|
|
36
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
37
|
+
"@vitest/coverage-v8": "4.1.10",
|
|
38
|
+
"eslint": "10.8.0",
|
|
39
|
+
"eslint-config-silverwind": "143.0.0",
|
|
40
40
|
"jest-extended": "7.0.0",
|
|
41
|
-
"tsdown": "0.22.
|
|
42
|
-
"tsdown-config-silverwind": "
|
|
41
|
+
"tsdown": "0.22.14",
|
|
42
|
+
"tsdown-config-silverwind": "4.0.3",
|
|
43
43
|
"typescript": "6.0.3",
|
|
44
|
-
"typescript-config-silverwind": "20.0.
|
|
45
|
-
"updates": "17.
|
|
46
|
-
"updates-config-silverwind": "4.0.
|
|
47
|
-
"versions": "15.1.
|
|
48
|
-
"vitest": "4.1.
|
|
49
|
-
"vitest-config-silverwind": "11.
|
|
44
|
+
"typescript-config-silverwind": "20.0.3",
|
|
45
|
+
"updates": "17.19.2",
|
|
46
|
+
"updates-config-silverwind": "4.0.4",
|
|
47
|
+
"versions": "15.1.4",
|
|
48
|
+
"vitest": "4.1.10",
|
|
49
|
+
"vitest-config-silverwind": "11.4.0"
|
|
50
50
|
}
|
|
51
51
|
}
|