cidr-tools 11.0.8 → 11.0.10
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 +150 -100
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseIp, stringifyIp, normalizeIp } from "ip-bigint";
|
|
2
2
|
const bits = { 4: 32, 6: 128 };
|
|
3
3
|
function uniq(arr) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
function cidrVersion(cidr) {
|
|
7
|
-
return cidr.includes("/") ? ipVersion(cidr) : 0;
|
|
8
|
-
}
|
|
9
|
-
function compare(a, b) {
|
|
10
|
-
const { number: aNum, version: aVersion } = parseIp(a.replace(/\/.+/, ""));
|
|
11
|
-
const { number: bNum, version: bVersion } = parseIp(b.replace(/\/.+/, ""));
|
|
12
|
-
if (aVersion === bVersion) {
|
|
13
|
-
return aNum - bNum > 0n ? 1 : aNum - bNum < 0n ? -1 : 0;
|
|
14
|
-
} else {
|
|
15
|
-
return aVersion > bVersion ? 1 : 0;
|
|
16
|
-
}
|
|
4
|
+
const set = new Set(arr);
|
|
5
|
+
return set.size === arr.length ? arr : Array.from(set);
|
|
17
6
|
}
|
|
18
7
|
function doNormalize(cidr, { compress = true, hexify = false } = {}) {
|
|
19
8
|
const { start, end, prefix, version, prefixPresent } = parseCidr(cidr);
|
|
@@ -32,51 +21,74 @@ function normalizeCidr(cidr, opts) {
|
|
|
32
21
|
}
|
|
33
22
|
}
|
|
34
23
|
function parseCidr(str) {
|
|
35
|
-
const cidrVer = cidrVersion(str);
|
|
36
24
|
const parsed = /* @__PURE__ */ Object.create(null);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (
|
|
44
|
-
cidr = `${str}/${bits[version2]}`;
|
|
45
|
-
parsed.version = version2;
|
|
46
|
-
} else {
|
|
25
|
+
const slashIndex = str.indexOf("/");
|
|
26
|
+
let ipPart;
|
|
27
|
+
let prefix;
|
|
28
|
+
if (slashIndex !== -1) {
|
|
29
|
+
ipPart = str.substring(0, slashIndex);
|
|
30
|
+
prefix = str.substring(slashIndex + 1);
|
|
31
|
+
if (!/^[0-9]+$/.test(prefix)) {
|
|
47
32
|
throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
48
33
|
}
|
|
34
|
+
parsed.prefixPresent = true;
|
|
35
|
+
} else {
|
|
36
|
+
ipPart = str;
|
|
37
|
+
parsed.prefixPresent = false;
|
|
38
|
+
prefix = "";
|
|
49
39
|
}
|
|
50
|
-
const
|
|
51
|
-
if (
|
|
40
|
+
const { number, version, ipv4mapped, scopeid } = parseIp(ipPart);
|
|
41
|
+
if (!version) {
|
|
52
42
|
throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
53
43
|
}
|
|
54
|
-
|
|
44
|
+
if (!parsed.prefixPresent) {
|
|
45
|
+
prefix = String(bits[version]);
|
|
46
|
+
}
|
|
47
|
+
parsed.version = version;
|
|
55
48
|
parsed.ip = stringifyIp({ number, version, ipv4mapped, scopeid });
|
|
56
49
|
parsed.cidr = `${parsed.ip}/${prefix}`;
|
|
57
50
|
parsed.prefix = prefix;
|
|
58
|
-
parsed.prefixPresent = Boolean(cidrVer);
|
|
59
51
|
const numBits = bits[version];
|
|
60
|
-
const hostBits =
|
|
61
|
-
const mask = hostBits >
|
|
52
|
+
const hostBits = numBits - Number(prefix);
|
|
53
|
+
const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
|
|
62
54
|
parsed.start = number & ~mask;
|
|
63
55
|
parsed.end = number | mask;
|
|
64
56
|
return parsed;
|
|
65
57
|
}
|
|
66
|
-
function
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
58
|
+
function parseCidrLean(str) {
|
|
59
|
+
const slashIndex = str.indexOf("/");
|
|
60
|
+
let ipPart;
|
|
61
|
+
let prefixNum;
|
|
62
|
+
if (slashIndex !== -1) {
|
|
63
|
+
ipPart = str.substring(0, slashIndex);
|
|
64
|
+
const prefixStr = str.substring(slashIndex + 1);
|
|
65
|
+
if (!/^[0-9]+$/.test(prefixStr)) {
|
|
66
|
+
throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
67
|
+
}
|
|
68
|
+
prefixNum = Number(prefixStr);
|
|
69
|
+
} else {
|
|
70
|
+
ipPart = str;
|
|
71
|
+
prefixNum = -1;
|
|
72
|
+
}
|
|
73
|
+
const { number, version } = parseIp(ipPart);
|
|
74
|
+
if (!version) {
|
|
75
|
+
throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
76
|
+
}
|
|
77
|
+
if (prefixNum === -1) {
|
|
78
|
+
prefixNum = bits[version];
|
|
79
|
+
}
|
|
80
|
+
const numBits = bits[version];
|
|
81
|
+
const hostBits = numBits - prefixNum;
|
|
82
|
+
const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
|
|
83
|
+
return {
|
|
84
|
+
start: number & ~mask,
|
|
85
|
+
end: number | mask,
|
|
86
|
+
version
|
|
87
|
+
};
|
|
75
88
|
}
|
|
76
|
-
function
|
|
77
|
-
const parts = [];
|
|
89
|
+
function excludeNetsParts(a, b) {
|
|
78
90
|
if (a.start > b.end || a.end < b.start) {
|
|
79
|
-
return [a
|
|
91
|
+
return [a];
|
|
80
92
|
}
|
|
81
93
|
if (a.start === b.start && a.end === b.end) {
|
|
82
94
|
return [];
|
|
@@ -84,6 +96,7 @@ function excludeNets(a, b, v) {
|
|
|
84
96
|
if (a.start > b.start && a.end < b.end) {
|
|
85
97
|
return [];
|
|
86
98
|
}
|
|
99
|
+
const parts = [];
|
|
87
100
|
if (a.start < b.start && a.end <= b.end) {
|
|
88
101
|
parts.push({ start: a.start, end: b.start - 1n });
|
|
89
102
|
}
|
|
@@ -98,11 +111,9 @@ function excludeNets(a, b, v) {
|
|
|
98
111
|
}
|
|
99
112
|
const remaining = [];
|
|
100
113
|
for (const part of parts) {
|
|
101
|
-
|
|
102
|
-
remaining.push(formatPart(subpart, v));
|
|
103
|
-
}
|
|
114
|
+
subparts(part, remaining);
|
|
104
115
|
}
|
|
105
|
-
return
|
|
116
|
+
return remaining;
|
|
106
117
|
}
|
|
107
118
|
function biggestPowerOfTwo(num) {
|
|
108
119
|
if (num === 0n) return 0n;
|
|
@@ -114,26 +125,30 @@ function biggestPowerOfTwo(num) {
|
|
|
114
125
|
}
|
|
115
126
|
return 1n << b;
|
|
116
127
|
}
|
|
117
|
-
function subparts(part) {
|
|
128
|
+
function subparts(part, output) {
|
|
129
|
+
if (!output) output = [];
|
|
118
130
|
if (part.end < part.start) {
|
|
119
|
-
return
|
|
131
|
+
return output;
|
|
120
132
|
}
|
|
121
133
|
if (part.end === part.start) {
|
|
122
|
-
|
|
134
|
+
output.push(part);
|
|
135
|
+
return output;
|
|
123
136
|
}
|
|
124
137
|
if (part.end - part.start === 1n) {
|
|
125
138
|
if (part.end % 2n === 0n) {
|
|
126
|
-
|
|
139
|
+
output.push({ start: part.start, end: part.start }, { start: part.end, end: part.end });
|
|
127
140
|
} else {
|
|
128
|
-
|
|
141
|
+
output.push({ start: part.start, end: part.end });
|
|
129
142
|
}
|
|
143
|
+
return output;
|
|
130
144
|
}
|
|
131
145
|
const size = diff(part.end, part.start);
|
|
132
146
|
let biggest = biggestPowerOfTwo(size);
|
|
133
147
|
let start;
|
|
134
148
|
let end;
|
|
135
|
-
if (size === biggest && part.start
|
|
136
|
-
|
|
149
|
+
if (size === biggest && part.start % biggest === 0n) {
|
|
150
|
+
output.push(part);
|
|
151
|
+
return output;
|
|
137
152
|
} else if (part.start % biggest === 0n) {
|
|
138
153
|
start = part.start;
|
|
139
154
|
end = start + biggest - 1n;
|
|
@@ -151,14 +166,14 @@ function subparts(part) {
|
|
|
151
166
|
end = start + biggest - 1n;
|
|
152
167
|
}
|
|
153
168
|
}
|
|
154
|
-
let parts = [{ start, end }];
|
|
155
169
|
if (start !== part.start) {
|
|
156
|
-
|
|
170
|
+
subparts({ start: part.start, end: start - 1n }, output);
|
|
157
171
|
}
|
|
172
|
+
output.push({ start, end });
|
|
158
173
|
if (end !== part.end) {
|
|
159
|
-
|
|
174
|
+
subparts({ start: end + 1n, end: part.end }, output);
|
|
160
175
|
}
|
|
161
|
-
return
|
|
176
|
+
return output;
|
|
162
177
|
}
|
|
163
178
|
function diff(a, b) {
|
|
164
179
|
return a + 1n - b;
|
|
@@ -208,88 +223,123 @@ function doMerge(maps) {
|
|
|
208
223
|
if (marker.end) depth -= marker.end;
|
|
209
224
|
const next = numbers[index2 + 1];
|
|
210
225
|
if (marker.end && depth === 0 && next !== void 0 && next - number > 1n) {
|
|
211
|
-
|
|
212
|
-
merged.push(sub);
|
|
213
|
-
}
|
|
226
|
+
subparts({ start, end }, merged);
|
|
214
227
|
start = null;
|
|
215
228
|
end = null;
|
|
216
229
|
} else if (index2 === numbers.length - 1) {
|
|
217
|
-
|
|
218
|
-
merged.push(sub);
|
|
219
|
-
}
|
|
230
|
+
subparts({ start, end }, merged);
|
|
220
231
|
}
|
|
221
232
|
}
|
|
222
233
|
return merged;
|
|
223
234
|
}
|
|
224
235
|
function mergeCidr(nets) {
|
|
225
|
-
const arr = uniq(Array.isArray(nets) ? nets : [nets]).map(
|
|
236
|
+
const arr = uniq(Array.isArray(nets) ? nets : [nets]).map(parseCidrLean);
|
|
226
237
|
const maps = mapNets(arr);
|
|
227
|
-
const merged =
|
|
238
|
+
const merged = [];
|
|
228
239
|
for (const v of [4, 6]) {
|
|
229
|
-
|
|
240
|
+
for (const part of doMerge(maps[v])) {
|
|
241
|
+
merged.push(formatPart(part, v));
|
|
242
|
+
}
|
|
230
243
|
}
|
|
231
|
-
return
|
|
244
|
+
return merged;
|
|
232
245
|
}
|
|
233
246
|
function excludeCidr(base, excl) {
|
|
234
|
-
const
|
|
235
|
-
const
|
|
247
|
+
const baseArr = uniq(Array.isArray(base) ? base : [base]).map(parseCidrLean);
|
|
248
|
+
const exclArr = uniq(Array.isArray(excl) ? excl : [excl]).map(parseCidrLean);
|
|
249
|
+
const baseMaps = mapNets(baseArr);
|
|
250
|
+
const exclMaps = mapNets(exclArr);
|
|
236
251
|
const bases = { 4: [], 6: [] };
|
|
237
252
|
const excls = { 4: [], 6: [] };
|
|
238
|
-
for (const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
for (const exclnet of exclnets) {
|
|
243
|
-
const version = cidrVersion(exclnet);
|
|
244
|
-
if (version) excls[version].push(exclnet);
|
|
253
|
+
for (const v of [4, 6]) {
|
|
254
|
+
bases[v] = doMerge(baseMaps[v]);
|
|
255
|
+
excls[v] = doMerge(exclMaps[v]);
|
|
245
256
|
}
|
|
246
257
|
for (const v of [4, 6]) {
|
|
247
|
-
for (const
|
|
248
|
-
const excl2 = parseCidr(exclcidr);
|
|
258
|
+
for (const exclPart of excls[v]) {
|
|
249
259
|
const newBases = [];
|
|
250
|
-
for (const
|
|
251
|
-
|
|
260
|
+
for (const basePart of bases[v]) {
|
|
261
|
+
for (const part of excludeNetsParts(basePart, exclPart)) {
|
|
262
|
+
newBases.push(part);
|
|
263
|
+
}
|
|
252
264
|
}
|
|
253
265
|
bases[v] = newBases;
|
|
254
266
|
}
|
|
255
267
|
}
|
|
256
|
-
|
|
268
|
+
const result = [];
|
|
269
|
+
for (const v of [4, 6]) {
|
|
270
|
+
for (const part of bases[v]) {
|
|
271
|
+
result.push(formatPart(part, v));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return result;
|
|
257
275
|
}
|
|
258
276
|
function* expandCidr(nets) {
|
|
259
277
|
const arr = uniq(Array.isArray(nets) ? nets : [nets]);
|
|
260
278
|
for (const net of mergeCidr(arr)) {
|
|
261
|
-
const { start, end, version } =
|
|
279
|
+
const { start, end, version } = parseCidrLean(net);
|
|
262
280
|
for (let number = start; number <= end; number++) {
|
|
263
281
|
yield normalizeIp(stringifyIp({ number, version }));
|
|
264
282
|
}
|
|
265
283
|
}
|
|
266
284
|
}
|
|
267
285
|
function overlapCidr(a, b) {
|
|
268
|
-
const aNets = uniq(Array.isArray(a) ? a : [a]).map(
|
|
269
|
-
const bNets = uniq(Array.isArray(b) ? b : [b]).map(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
286
|
+
const aNets = uniq(Array.isArray(a) ? a : [a]).map(parseCidrLean);
|
|
287
|
+
const bNets = uniq(Array.isArray(b) ? b : [b]).map(parseCidrLean);
|
|
288
|
+
const aByVersion = { 4: [], 6: [] };
|
|
289
|
+
const bByVersion = { 4: [], 6: [] };
|
|
290
|
+
for (const n of aNets) aByVersion[n.version].push(n);
|
|
291
|
+
for (const n of bNets) bByVersion[n.version].push(n);
|
|
292
|
+
for (const v of [4, 6]) {
|
|
293
|
+
const aVer = aByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
|
|
294
|
+
const bVer = bByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
|
|
295
|
+
let i = 0, j = 0;
|
|
296
|
+
while (i < aVer.length && j < bVer.length) {
|
|
297
|
+
const aNet = aVer[i];
|
|
298
|
+
const bNet = bVer[j];
|
|
299
|
+
if (aNet.start <= bNet.end && bNet.start <= aNet.end) return true;
|
|
300
|
+
if (aNet.end < bNet.end) i++;
|
|
301
|
+
else j++;
|
|
274
302
|
}
|
|
275
303
|
}
|
|
276
304
|
return false;
|
|
277
305
|
}
|
|
278
306
|
function containsCidr(a, b) {
|
|
279
|
-
const aNets = uniq(Array.isArray(a) ? a : [a]).map(
|
|
280
|
-
const bNets = uniq(Array.isArray(b) ? b : [b]).map(
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
for (const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
307
|
+
const aNets = uniq(Array.isArray(a) ? a : [a]).map(parseCidrLean);
|
|
308
|
+
const bNets = uniq(Array.isArray(b) ? b : [b]).map(parseCidrLean);
|
|
309
|
+
const aByVersion = { 4: [], 6: [] };
|
|
310
|
+
const bByVersion = { 4: [], 6: [] };
|
|
311
|
+
for (const n of aNets) aByVersion[n.version].push(n);
|
|
312
|
+
for (const n of bNets) bByVersion[n.version].push(n);
|
|
313
|
+
for (const v of [4, 6]) {
|
|
314
|
+
const containers = aByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
|
|
315
|
+
const targets = bByVersion[v];
|
|
316
|
+
if (targets.length === 0) continue;
|
|
317
|
+
if (containers.length === 0) return false;
|
|
318
|
+
const maxEnd = new Array(containers.length);
|
|
319
|
+
maxEnd[0] = containers[0].end;
|
|
320
|
+
for (let i = 1; i < containers.length; i++) {
|
|
321
|
+
if (containers[i].end > maxEnd[i - 1]) {
|
|
322
|
+
maxEnd[i] = containers[i].end;
|
|
323
|
+
} else {
|
|
324
|
+
maxEnd[i] = maxEnd[i - 1];
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
for (const target of targets) {
|
|
328
|
+
let lo = 0, hi = containers.length - 1;
|
|
329
|
+
let idx = -1;
|
|
330
|
+
while (lo <= hi) {
|
|
331
|
+
const mid = lo + hi >> 1;
|
|
332
|
+
if (containers[mid].start <= target.start) {
|
|
333
|
+
idx = mid;
|
|
334
|
+
lo = mid + 1;
|
|
335
|
+
} else {
|
|
336
|
+
hi = mid - 1;
|
|
337
|
+
}
|
|
289
338
|
}
|
|
339
|
+
if (idx < 0 || maxEnd[idx] < target.end) return false;
|
|
290
340
|
}
|
|
291
341
|
}
|
|
292
|
-
return
|
|
342
|
+
return true;
|
|
293
343
|
}
|
|
294
344
|
const index = {
|
|
295
345
|
mergeCidr,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cidr-tools",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.10",
|
|
4
4
|
"author": "silverwind <me@silverwind.io>",
|
|
5
5
|
"description": "Tools to work with IPv4 and IPv6 CIDR",
|
|
6
6
|
"repository": "silverwind/cidr-tools",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"node": ">=18"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"ip-bigint": "^8.2.
|
|
20
|
+
"ip-bigint": "^8.2.6"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@typescript/native-preview": "7.0.0-dev.20260202.1",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"typescript": "5.9.3",
|
|
28
28
|
"typescript-config-silverwind": "14.0.0",
|
|
29
29
|
"updates": "17.1.0",
|
|
30
|
+
"updates-config-silverwind": "1.0.3",
|
|
30
31
|
"versions": "14.1.0",
|
|
31
32
|
"vite": "7.3.1",
|
|
32
33
|
"vite-config-silverwind": "6.0.9",
|