cidr-tools 11.1.0 → 11.2.1
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 +366 -131
- package/package.json +9 -9
package/dist/index.js
CHANGED
|
@@ -29,8 +29,23 @@ function parseIPv4Fast(s) {
|
|
|
29
29
|
function formatIPv4Fast(n) {
|
|
30
30
|
return `${n >>> 24 & 255}.${n >>> 16 & 255}.${n >>> 8 & 255}.${n & 255}`;
|
|
31
31
|
}
|
|
32
|
+
function parsePrefixNum(str, slashIndex) {
|
|
33
|
+
if (slashIndex === -1) return -1;
|
|
34
|
+
if (slashIndex + 1 >= str.length) throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
35
|
+
let prefixNum = 0;
|
|
36
|
+
for (let i = slashIndex + 1; i < str.length; i++) {
|
|
37
|
+
const c = str.charCodeAt(i);
|
|
38
|
+
if (c < 48 || c > 57) throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
39
|
+
prefixNum = prefixNum * 10 + (c - 48);
|
|
40
|
+
}
|
|
41
|
+
return prefixNum;
|
|
42
|
+
}
|
|
32
43
|
function doNormalize(cidr, { compress = true, hexify = false } = {}) {
|
|
33
44
|
const { start, end, prefix, version, prefixPresent } = parseCidr(cidr);
|
|
45
|
+
if (version === 4) {
|
|
46
|
+
const ip = formatIPv4Fast(Number(start));
|
|
47
|
+
return start !== end || prefixPresent ? `${ip}/${prefix}` : ip;
|
|
48
|
+
}
|
|
34
49
|
if (start !== end || prefixPresent) return `${normalizeIp(stringifyIp({
|
|
35
50
|
number: start,
|
|
36
51
|
version
|
|
@@ -52,28 +67,55 @@ function normalizeCidr(cidr, opts) {
|
|
|
52
67
|
function parseCidr(str) {
|
|
53
68
|
const slashIndex = str.indexOf("/");
|
|
54
69
|
let ipPart;
|
|
55
|
-
let
|
|
70
|
+
let prefixNum;
|
|
56
71
|
let prefixPresent;
|
|
57
72
|
if (slashIndex !== -1) {
|
|
58
73
|
ipPart = str.substring(0, slashIndex);
|
|
59
|
-
|
|
60
|
-
if (!/^[0-9]+$/.test(prefix)) throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
74
|
+
prefixNum = parsePrefixNum(str, slashIndex);
|
|
61
75
|
prefixPresent = true;
|
|
62
76
|
} else {
|
|
63
77
|
ipPart = str;
|
|
78
|
+
prefixNum = -1;
|
|
64
79
|
prefixPresent = false;
|
|
65
|
-
|
|
80
|
+
}
|
|
81
|
+
if (!ipPart.includes(":")) {
|
|
82
|
+
const v4num = parseIPv4Fast(ipPart);
|
|
83
|
+
if (v4num !== -1) {
|
|
84
|
+
if (prefixNum === -1) prefixNum = 32;
|
|
85
|
+
const ip = formatIPv4Fast(v4num);
|
|
86
|
+
const prefix = String(prefixNum);
|
|
87
|
+
const hostBits = 32 - prefixNum;
|
|
88
|
+
let startNum, endNum;
|
|
89
|
+
if (hostBits >= 32) {
|
|
90
|
+
startNum = 0;
|
|
91
|
+
endNum = 4294967295;
|
|
92
|
+
} else {
|
|
93
|
+
const mask = hostBits > 0 ? (1 << hostBits >>> 0) - 1 : 0;
|
|
94
|
+
startNum = (v4num & ~mask) >>> 0;
|
|
95
|
+
endNum = (v4num | mask) >>> 0;
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
cidr: `${ip}/${prefix}`,
|
|
99
|
+
ip,
|
|
100
|
+
version: 4,
|
|
101
|
+
prefix,
|
|
102
|
+
prefixPresent,
|
|
103
|
+
start: BigInt(startNum),
|
|
104
|
+
end: BigInt(endNum)
|
|
105
|
+
};
|
|
106
|
+
}
|
|
66
107
|
}
|
|
67
108
|
const { number, version, ipv4mapped, scopeid } = parseIp(ipPart);
|
|
68
109
|
if (!version) throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
69
|
-
if (
|
|
110
|
+
if (prefixNum === -1) prefixNum = bits[version];
|
|
111
|
+
const prefix = String(prefixNum);
|
|
70
112
|
const ip = stringifyIp({
|
|
71
113
|
number,
|
|
72
114
|
version,
|
|
73
115
|
ipv4mapped,
|
|
74
116
|
scopeid
|
|
75
117
|
});
|
|
76
|
-
const hostBits = bits[version] -
|
|
118
|
+
const hostBits = bits[version] - prefixNum;
|
|
77
119
|
const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
|
|
78
120
|
return {
|
|
79
121
|
cidr: `${ip}/${prefix}`,
|
|
@@ -91,13 +133,7 @@ function parseCidrLean(str) {
|
|
|
91
133
|
let prefixNum;
|
|
92
134
|
if (slashIndex !== -1) {
|
|
93
135
|
ipPart = str.substring(0, slashIndex);
|
|
94
|
-
|
|
95
|
-
prefixNum = 0;
|
|
96
|
-
for (let i = slashIndex + 1; i < str.length; i++) {
|
|
97
|
-
const c = str.charCodeAt(i);
|
|
98
|
-
if (c < 48 || c > 57) throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
99
|
-
prefixNum = prefixNum * 10 + (c - 48);
|
|
100
|
-
}
|
|
136
|
+
prefixNum = parsePrefixNum(str, slashIndex);
|
|
101
137
|
} else {
|
|
102
138
|
ipPart = str;
|
|
103
139
|
prefixNum = -1;
|
|
@@ -108,14 +144,14 @@ function parseCidrLean(str) {
|
|
|
108
144
|
if (prefixNum === -1) prefixNum = 32;
|
|
109
145
|
const hostBits = 32 - prefixNum;
|
|
110
146
|
if (hostBits >= 32) return {
|
|
111
|
-
start:
|
|
112
|
-
end:
|
|
147
|
+
start: 0,
|
|
148
|
+
end: 4294967295,
|
|
113
149
|
version: 4
|
|
114
150
|
};
|
|
115
151
|
const mask = hostBits > 0 ? (1 << hostBits >>> 0) - 1 : 0;
|
|
116
152
|
return {
|
|
117
|
-
start:
|
|
118
|
-
end:
|
|
153
|
+
start: (v4num & ~mask) >>> 0,
|
|
154
|
+
end: (v4num | mask) >>> 0,
|
|
119
155
|
version: 4
|
|
120
156
|
};
|
|
121
157
|
}
|
|
@@ -124,18 +160,114 @@ function parseCidrLean(str) {
|
|
|
124
160
|
if (!version) throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
125
161
|
if (prefixNum === -1) prefixNum = bits[version];
|
|
126
162
|
const hostBits = bits[version] - prefixNum;
|
|
163
|
+
if (version === 4) {
|
|
164
|
+
const num = Number(number);
|
|
165
|
+
if (hostBits >= 32) return {
|
|
166
|
+
start: 0,
|
|
167
|
+
end: 4294967295,
|
|
168
|
+
version: 4
|
|
169
|
+
};
|
|
170
|
+
const mask = hostBits > 0 ? (1 << hostBits >>> 0) - 1 : 0;
|
|
171
|
+
return {
|
|
172
|
+
start: (num & ~mask) >>> 0,
|
|
173
|
+
end: (num | mask) >>> 0,
|
|
174
|
+
version: 4
|
|
175
|
+
};
|
|
176
|
+
}
|
|
127
177
|
const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
|
|
128
178
|
return {
|
|
129
179
|
start: number & ~mask,
|
|
130
180
|
end: number | mask,
|
|
131
|
-
version
|
|
181
|
+
version: 6
|
|
132
182
|
};
|
|
133
183
|
}
|
|
184
|
+
function bigintBitLength(n) {
|
|
185
|
+
if (n === 0n) return 0;
|
|
186
|
+
let len = 0;
|
|
187
|
+
if (n >= 18446744073709551616n) {
|
|
188
|
+
n >>= 64n;
|
|
189
|
+
len = 64;
|
|
190
|
+
}
|
|
191
|
+
while (n >= 4294967296n) {
|
|
192
|
+
n >>= 32n;
|
|
193
|
+
len += 32;
|
|
194
|
+
}
|
|
195
|
+
return len + 32 - Math.clz32(Number(n));
|
|
196
|
+
}
|
|
134
197
|
function biggestPowerOfTwo(num) {
|
|
135
198
|
if (num === 0n) return 0n;
|
|
136
|
-
return 1n << BigInt(num
|
|
199
|
+
return 1n << BigInt(bigintBitLength(num) - 1);
|
|
200
|
+
}
|
|
201
|
+
function biggestPowerOfTwo4(num) {
|
|
202
|
+
if (num === 0) return 0;
|
|
203
|
+
if (num >= 4294967296) return 4294967296;
|
|
204
|
+
return 1 << 31 - Math.clz32(num) >>> 0;
|
|
205
|
+
}
|
|
206
|
+
function subparts4(pStart, pEnd, output) {
|
|
207
|
+
if (pEnd < pStart) return;
|
|
208
|
+
if (pEnd === pStart) {
|
|
209
|
+
output.push({
|
|
210
|
+
start: pStart,
|
|
211
|
+
end: pEnd
|
|
212
|
+
});
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (pEnd - pStart === 1) {
|
|
216
|
+
if (pEnd % 2 === 0) output.push({
|
|
217
|
+
start: pStart,
|
|
218
|
+
end: pStart
|
|
219
|
+
}, {
|
|
220
|
+
start: pEnd,
|
|
221
|
+
end: pEnd
|
|
222
|
+
});
|
|
223
|
+
else output.push({
|
|
224
|
+
start: pStart,
|
|
225
|
+
end: pEnd
|
|
226
|
+
});
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const size = pEnd - pStart + 1;
|
|
230
|
+
if ((size & size - 1) === 0 && pStart % size === 0) {
|
|
231
|
+
output.push({
|
|
232
|
+
start: pStart,
|
|
233
|
+
end: pEnd
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
let biggest = biggestPowerOfTwo4(size);
|
|
238
|
+
let start;
|
|
239
|
+
let end;
|
|
240
|
+
if (size === biggest && pStart % biggest === 0) {
|
|
241
|
+
output.push({
|
|
242
|
+
start: pStart,
|
|
243
|
+
end: pEnd
|
|
244
|
+
});
|
|
245
|
+
return;
|
|
246
|
+
} else if (pStart % biggest === 0) {
|
|
247
|
+
start = pStart;
|
|
248
|
+
end = start + biggest - 1;
|
|
249
|
+
} else {
|
|
250
|
+
start = Math.floor(pEnd / biggest) * biggest;
|
|
251
|
+
if (start + biggest - 1 > pEnd) {
|
|
252
|
+
start = (Math.floor(pEnd / biggest) - 1) * biggest;
|
|
253
|
+
while (start < pStart) {
|
|
254
|
+
biggest /= 2;
|
|
255
|
+
start = (Math.floor(pEnd / biggest) - 1) * biggest;
|
|
256
|
+
}
|
|
257
|
+
end = start + biggest - 1;
|
|
258
|
+
} else {
|
|
259
|
+
start = Math.floor(pEnd / biggest) * biggest;
|
|
260
|
+
end = start + biggest - 1;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (start !== pStart) subparts4(pStart, start - 1, output);
|
|
264
|
+
output.push({
|
|
265
|
+
start,
|
|
266
|
+
end
|
|
267
|
+
});
|
|
268
|
+
if (end !== pEnd) subparts4(end + 1, pEnd, output);
|
|
137
269
|
}
|
|
138
|
-
function
|
|
270
|
+
function subparts6(pStart, pEnd, output) {
|
|
139
271
|
if (pEnd < pStart) return;
|
|
140
272
|
if (pEnd === pStart) {
|
|
141
273
|
output.push({
|
|
@@ -158,58 +290,86 @@ function subparts(pStart, pEnd, output) {
|
|
|
158
290
|
});
|
|
159
291
|
return;
|
|
160
292
|
}
|
|
161
|
-
const size =
|
|
293
|
+
const size = pEnd - pStart + 1n;
|
|
294
|
+
if ((size & size - 1n) === 0n && (pStart & size - 1n) === 0n) {
|
|
295
|
+
output.push({
|
|
296
|
+
start: pStart,
|
|
297
|
+
end: pEnd
|
|
298
|
+
});
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
162
301
|
let biggest = biggestPowerOfTwo(size);
|
|
163
302
|
let start;
|
|
164
303
|
let end;
|
|
165
|
-
if (size === biggest && pStart
|
|
304
|
+
if (size === biggest && (pStart & biggest - 1n) === 0n) {
|
|
166
305
|
output.push({
|
|
167
306
|
start: pStart,
|
|
168
307
|
end: pEnd
|
|
169
308
|
});
|
|
170
309
|
return;
|
|
171
|
-
} else if (pStart
|
|
310
|
+
} else if ((pStart & biggest - 1n) === 0n) {
|
|
172
311
|
start = pStart;
|
|
173
312
|
end = start + biggest - 1n;
|
|
174
313
|
} else {
|
|
175
|
-
start = pEnd
|
|
314
|
+
start = pEnd & -biggest;
|
|
176
315
|
if (start + biggest - 1n > pEnd) {
|
|
177
|
-
start = (pEnd
|
|
316
|
+
start = (pEnd & -biggest) - biggest;
|
|
178
317
|
while (start < pStart) {
|
|
179
|
-
biggest
|
|
180
|
-
start = (pEnd
|
|
318
|
+
biggest >>= 1n;
|
|
319
|
+
start = (pEnd & -biggest) - biggest;
|
|
181
320
|
}
|
|
182
321
|
end = start + biggest - 1n;
|
|
183
322
|
} else {
|
|
184
|
-
start = pEnd
|
|
323
|
+
start = pEnd & -biggest;
|
|
185
324
|
end = start + biggest - 1n;
|
|
186
325
|
}
|
|
187
326
|
}
|
|
188
|
-
if (start !== pStart)
|
|
327
|
+
if (start !== pStart) subparts6(pStart, start - 1n, output);
|
|
189
328
|
output.push({
|
|
190
329
|
start,
|
|
191
330
|
end
|
|
192
331
|
});
|
|
193
|
-
if (end !== pEnd)
|
|
332
|
+
if (end !== pEnd) subparts6(end + 1n, pEnd, output);
|
|
194
333
|
}
|
|
195
|
-
function
|
|
196
|
-
|
|
334
|
+
function formatPart4(part) {
|
|
335
|
+
const ip = formatIPv4Fast(part.start);
|
|
336
|
+
const size = part.end - part.start + 1;
|
|
337
|
+
return `${ip}/${32 - (size <= 1 ? 0 : size >= 4294967296 ? 32 : 31 - Math.clz32(size))}`;
|
|
197
338
|
}
|
|
198
|
-
function
|
|
199
|
-
if (version === 4) {
|
|
200
|
-
const ip = formatIPv4Fast(Number(part.start));
|
|
201
|
-
const sizeNum = Number(part.end - part.start) + 1;
|
|
202
|
-
return `${ip}/${32 - (sizeNum <= 1 ? 0 : sizeNum >= 4294967296 ? 32 : 31 - Math.clz32(sizeNum))}`;
|
|
203
|
-
}
|
|
339
|
+
function formatPart6(part) {
|
|
204
340
|
const ip = stringifyIp({
|
|
205
341
|
number: part.start,
|
|
206
|
-
version
|
|
342
|
+
version: 6
|
|
207
343
|
});
|
|
208
|
-
const size =
|
|
209
|
-
|
|
210
|
-
return `${ip}/${bits[version] - hostBits}`;
|
|
344
|
+
const size = part.end - part.start + 1n;
|
|
345
|
+
return `${ip}/${128 - (size <= 1n ? 0 : bigintBitLength(size) - 1)}`;
|
|
211
346
|
}
|
|
212
|
-
function
|
|
347
|
+
function mergeIntervalsRaw4(nets) {
|
|
348
|
+
if (nets.length === 0) return [];
|
|
349
|
+
nets.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
350
|
+
const merged = [];
|
|
351
|
+
let curStart = nets[0].start;
|
|
352
|
+
let curEnd = nets[0].end;
|
|
353
|
+
for (let i = 1; i < nets.length; i++) {
|
|
354
|
+
const { start, end } = nets[i];
|
|
355
|
+
if (start <= curEnd + 1) {
|
|
356
|
+
if (end > curEnd) curEnd = end;
|
|
357
|
+
} else {
|
|
358
|
+
merged.push({
|
|
359
|
+
start: curStart,
|
|
360
|
+
end: curEnd
|
|
361
|
+
});
|
|
362
|
+
curStart = start;
|
|
363
|
+
curEnd = end;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
merged.push({
|
|
367
|
+
start: curStart,
|
|
368
|
+
end: curEnd
|
|
369
|
+
});
|
|
370
|
+
return merged;
|
|
371
|
+
}
|
|
372
|
+
function mergeIntervalsRaw6(nets) {
|
|
213
373
|
if (nets.length === 0) return [];
|
|
214
374
|
nets.sort((a, b) => a.start > b.start ? 1 : a.start < b.start ? -1 : a.end > b.end ? 1 : a.end < b.end ? -1 : 0);
|
|
215
375
|
const merged = [];
|
|
@@ -234,12 +394,42 @@ function mergeIntervalsRaw(nets) {
|
|
|
234
394
|
});
|
|
235
395
|
return merged;
|
|
236
396
|
}
|
|
237
|
-
function
|
|
397
|
+
function mergeIntervals4(nets) {
|
|
238
398
|
const merged = [];
|
|
239
|
-
for (const part of
|
|
399
|
+
for (const part of mergeIntervalsRaw4(nets)) subparts4(part.start, part.end, merged);
|
|
240
400
|
return merged;
|
|
241
401
|
}
|
|
242
|
-
function
|
|
402
|
+
function mergeIntervals6(nets) {
|
|
403
|
+
const merged = [];
|
|
404
|
+
for (const part of mergeIntervalsRaw6(nets)) subparts6(part.start, part.end, merged);
|
|
405
|
+
return merged;
|
|
406
|
+
}
|
|
407
|
+
function subtractSorted4(bases, excls) {
|
|
408
|
+
if (excls.length === 0) return bases;
|
|
409
|
+
if (bases.length === 0) return [];
|
|
410
|
+
const result = [];
|
|
411
|
+
let j = 0;
|
|
412
|
+
for (const base of bases) {
|
|
413
|
+
let start = base.start;
|
|
414
|
+
const end = base.end;
|
|
415
|
+
while (j < excls.length && excls[j].end < start) j++;
|
|
416
|
+
let k = j;
|
|
417
|
+
while (k < excls.length && excls[k].start <= end && start <= end) {
|
|
418
|
+
if (excls[k].start > start) result.push({
|
|
419
|
+
start,
|
|
420
|
+
end: excls[k].start - 1
|
|
421
|
+
});
|
|
422
|
+
start = excls[k].end + 1;
|
|
423
|
+
k++;
|
|
424
|
+
}
|
|
425
|
+
if (start <= end) result.push({
|
|
426
|
+
start,
|
|
427
|
+
end
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
return result;
|
|
431
|
+
}
|
|
432
|
+
function subtractSorted6(bases, excls) {
|
|
243
433
|
if (excls.length === 0) return bases;
|
|
244
434
|
if (bases.length === 0) return [];
|
|
245
435
|
const result = [];
|
|
@@ -266,83 +456,104 @@ function subtractSorted(bases, excls) {
|
|
|
266
456
|
}
|
|
267
457
|
/** Returns an array of merged networks */
|
|
268
458
|
function mergeCidr(nets) {
|
|
269
|
-
const arr =
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
459
|
+
const arr = Array.isArray(nets) ? nets : [nets];
|
|
460
|
+
const v4 = [];
|
|
461
|
+
const v6 = [];
|
|
462
|
+
for (const s of arr) {
|
|
463
|
+
const n = parseCidrLean(s);
|
|
464
|
+
if (n.version === 4) v4.push(n);
|
|
465
|
+
else v6.push(n);
|
|
466
|
+
}
|
|
275
467
|
const merged = [];
|
|
276
|
-
for (const
|
|
468
|
+
for (const part of mergeIntervals4(v4)) merged.push(formatPart4(part));
|
|
469
|
+
for (const part of mergeIntervals6(v6)) merged.push(formatPart6(part));
|
|
277
470
|
return merged;
|
|
278
471
|
}
|
|
279
472
|
/** Returns an array of merged remaining networks of the subtraction of `excludeNetworks` from `baseNetworks`. */
|
|
280
473
|
function excludeCidr(base, excl) {
|
|
281
|
-
const baseArr =
|
|
282
|
-
const exclArr =
|
|
283
|
-
const
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
474
|
+
const baseArr = Array.isArray(base) ? base : [base];
|
|
475
|
+
const exclArr = Array.isArray(excl) ? excl : [excl];
|
|
476
|
+
const v4base = [], v6base = [];
|
|
477
|
+
const v4excl = [], v6excl = [];
|
|
478
|
+
for (const s of baseArr) {
|
|
479
|
+
const n = parseCidrLean(s);
|
|
480
|
+
if (n.version === 4) v4base.push(n);
|
|
481
|
+
else v6base.push(n);
|
|
482
|
+
}
|
|
483
|
+
for (const s of exclArr) {
|
|
484
|
+
const n = parseCidrLean(s);
|
|
485
|
+
if (n.version === 4) v4excl.push(n);
|
|
486
|
+
else v6excl.push(n);
|
|
487
|
+
}
|
|
293
488
|
const result = [];
|
|
294
|
-
|
|
295
|
-
const remaining =
|
|
489
|
+
{
|
|
490
|
+
const remaining = subtractSorted4(mergeIntervalsRaw4(v4base), mergeIntervalsRaw4(v4excl));
|
|
296
491
|
const aligned = [];
|
|
297
|
-
for (const part of remaining)
|
|
298
|
-
for (const p of aligned) result.push(
|
|
492
|
+
for (const part of remaining) subparts4(part.start, part.end, aligned);
|
|
493
|
+
for (const p of aligned) result.push(formatPart4(p));
|
|
494
|
+
}
|
|
495
|
+
{
|
|
496
|
+
const remaining = subtractSorted6(mergeIntervalsRaw6(v6base), mergeIntervalsRaw6(v6excl));
|
|
497
|
+
const aligned = [];
|
|
498
|
+
for (const part of remaining) subparts6(part.start, part.end, aligned);
|
|
499
|
+
for (const p of aligned) result.push(formatPart6(p));
|
|
299
500
|
}
|
|
300
501
|
return result;
|
|
301
502
|
}
|
|
302
503
|
function* expandCidr(nets) {
|
|
303
|
-
const
|
|
304
|
-
const
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (byVersion[v].length === 0) continue;
|
|
311
|
-
const intervals = mergeIntervalsRaw(byVersion[v]);
|
|
312
|
-
if (v === 4) for (const part of intervals) {
|
|
313
|
-
const startNum = Number(part.start);
|
|
314
|
-
const endNum = Number(part.end);
|
|
315
|
-
for (let n = startNum; n <= endNum; n++) yield formatIPv4Fast(n);
|
|
316
|
-
}
|
|
317
|
-
else for (const part of intervals) for (let num = part.start; num <= part.end; num++) yield stringifyIp({
|
|
318
|
-
number: num,
|
|
319
|
-
version: 6
|
|
320
|
-
});
|
|
504
|
+
const arr = Array.isArray(nets) ? nets : [nets];
|
|
505
|
+
const v4 = [];
|
|
506
|
+
const v6 = [];
|
|
507
|
+
for (const s of arr) {
|
|
508
|
+
const n = parseCidrLean(s);
|
|
509
|
+
if (n.version === 4) v4.push(n);
|
|
510
|
+
else v6.push(n);
|
|
321
511
|
}
|
|
512
|
+
if (v4.length > 0) for (const part of mergeIntervalsRaw4(v4)) for (let n = part.start; n <= part.end; n++) yield formatIPv4Fast(n);
|
|
513
|
+
if (v6.length > 0) for (const part of mergeIntervalsRaw6(v6)) for (let num = part.start; num <= part.end; num++) yield stringifyIp({
|
|
514
|
+
number: num,
|
|
515
|
+
version: 6
|
|
516
|
+
});
|
|
322
517
|
}
|
|
323
518
|
/** Returns a boolean that indicates if `networksA` overlap (intersect) with `networksB`. */
|
|
324
519
|
function overlapCidr(a, b) {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
}
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
for (const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
520
|
+
if (!Array.isArray(a) && !Array.isArray(b)) {
|
|
521
|
+
const pa = parseCidrLean(a);
|
|
522
|
+
const pb = parseCidrLean(b);
|
|
523
|
+
if (pa.version !== pb.version) return false;
|
|
524
|
+
return pa.start <= pb.end && pb.start <= pa.end;
|
|
525
|
+
}
|
|
526
|
+
const aArr = Array.isArray(a) ? a : [a];
|
|
527
|
+
const bArr = Array.isArray(b) ? b : [b];
|
|
528
|
+
const v4a = [], v6a = [];
|
|
529
|
+
const v4b = [], v6b = [];
|
|
530
|
+
for (const s of aArr) {
|
|
531
|
+
const n = parseCidrLean(s);
|
|
532
|
+
if (n.version === 4) v4a.push(n);
|
|
533
|
+
else v6a.push(n);
|
|
534
|
+
}
|
|
535
|
+
for (const s of bArr) {
|
|
536
|
+
const n = parseCidrLean(s);
|
|
537
|
+
if (n.version === 4) v4b.push(n);
|
|
538
|
+
else v6b.push(n);
|
|
539
|
+
}
|
|
540
|
+
if (v4a.length > 0 && v4b.length > 0) {
|
|
541
|
+
v4a.sort((x, y) => x.start - y.start);
|
|
542
|
+
v4b.sort((x, y) => x.start - y.start);
|
|
543
|
+
let i = 0, j = 0;
|
|
544
|
+
while (i < v4a.length && j < v4b.length) {
|
|
545
|
+
if (v4a[i].start <= v4b[j].end && v4b[j].start <= v4a[i].end) return true;
|
|
546
|
+
if (v4a[i].end < v4b[j].end) i++;
|
|
547
|
+
else j++;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
if (v6a.length > 0 && v6b.length > 0) {
|
|
551
|
+
v6a.sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
|
|
552
|
+
v6b.sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
|
|
340
553
|
let i = 0, j = 0;
|
|
341
|
-
while (i <
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if (aNet.start <= bNet.end && bNet.start <= aNet.end) return true;
|
|
345
|
-
if (aNet.end < bNet.end) i++;
|
|
554
|
+
while (i < v6a.length && j < v6b.length) {
|
|
555
|
+
if (v6a[i].start <= v6b[j].end && v6b[j].start <= v6a[i].end) return true;
|
|
556
|
+
if (v6a[i].end < v6b[j].end) i++;
|
|
346
557
|
else j++;
|
|
347
558
|
}
|
|
348
559
|
}
|
|
@@ -350,33 +561,57 @@ function overlapCidr(a, b) {
|
|
|
350
561
|
}
|
|
351
562
|
/** Returns a boolean that indicates whether `networksA` fully contain all `networksB`. */
|
|
352
563
|
function containsCidr(a, b) {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
for (const
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
564
|
+
if (!Array.isArray(a) && !Array.isArray(b)) {
|
|
565
|
+
const pa = parseCidrLean(a);
|
|
566
|
+
const pb = parseCidrLean(b);
|
|
567
|
+
if (pa.version !== pb.version) return false;
|
|
568
|
+
return pa.start <= pb.start && pa.end >= pb.end;
|
|
569
|
+
}
|
|
570
|
+
const aArr = Array.isArray(a) ? a : [a];
|
|
571
|
+
const bArr = Array.isArray(b) ? b : [b];
|
|
572
|
+
const v4a = [], v6a = [];
|
|
573
|
+
const v4b = [], v6b = [];
|
|
574
|
+
for (const s of aArr) {
|
|
575
|
+
const n = parseCidrLean(s);
|
|
576
|
+
if (n.version === 4) v4a.push(n);
|
|
577
|
+
else v6a.push(n);
|
|
578
|
+
}
|
|
579
|
+
for (const s of bArr) {
|
|
580
|
+
const n = parseCidrLean(s);
|
|
581
|
+
if (n.version === 4) v4b.push(n);
|
|
582
|
+
else v6b.push(n);
|
|
583
|
+
}
|
|
584
|
+
if (v4b.length > 0) {
|
|
585
|
+
if (v4a.length === 0) return false;
|
|
586
|
+
v4a.sort((x, y) => x.start - y.start);
|
|
587
|
+
const maxEnd = new Array(v4a.length);
|
|
588
|
+
maxEnd[0] = v4a[0].end;
|
|
589
|
+
for (let i = 1; i < v4a.length; i++) maxEnd[i] = Math.max(v4a[i].end, maxEnd[i - 1]);
|
|
590
|
+
for (const target of v4b) {
|
|
591
|
+
let lo = 0, hi = v4a.length - 1;
|
|
592
|
+
let idx = -1;
|
|
593
|
+
while (lo <= hi) {
|
|
594
|
+
const mid = lo + hi >> 1;
|
|
595
|
+
if (v4a[mid].start <= target.start) {
|
|
596
|
+
idx = mid;
|
|
597
|
+
lo = mid + 1;
|
|
598
|
+
} else hi = mid - 1;
|
|
599
|
+
}
|
|
600
|
+
if (idx < 0 || maxEnd[idx] < target.end) return false;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
if (v6b.length > 0) {
|
|
604
|
+
if (v6a.length === 0) return false;
|
|
605
|
+
v6a.sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
|
|
606
|
+
const maxEnd = new Array(v6a.length);
|
|
607
|
+
maxEnd[0] = v6a[0].end;
|
|
608
|
+
for (let i = 1; i < v6a.length; i++) maxEnd[i] = v6a[i].end > maxEnd[i - 1] ? v6a[i].end : maxEnd[i - 1];
|
|
609
|
+
for (const target of v6b) {
|
|
610
|
+
let lo = 0, hi = v6a.length - 1;
|
|
376
611
|
let idx = -1;
|
|
377
612
|
while (lo <= hi) {
|
|
378
613
|
const mid = lo + hi >> 1;
|
|
379
|
-
if (
|
|
614
|
+
if (v6a[mid].start <= target.start) {
|
|
380
615
|
idx = mid;
|
|
381
616
|
lo = mid + 1;
|
|
382
617
|
} else hi = mid - 1;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cidr-tools",
|
|
3
|
-
"version": "11.1
|
|
3
|
+
"version": "11.2.1",
|
|
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,19 +17,19 @@
|
|
|
17
17
|
"node": ">=18"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"ip-bigint": "^8.2.
|
|
20
|
+
"ip-bigint": "^8.2.12"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@types/node": "25.
|
|
24
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
25
|
-
"eslint": "9.39.
|
|
26
|
-
"eslint-config-silverwind": "
|
|
23
|
+
"@types/node": "25.4.0",
|
|
24
|
+
"@typescript/native-preview": "7.0.0-dev.20260311.1",
|
|
25
|
+
"eslint": "9.39.4",
|
|
26
|
+
"eslint-config-silverwind": "124.0.7",
|
|
27
27
|
"jest-extended": "7.0.0",
|
|
28
|
-
"tsdown": "0.21.
|
|
29
|
-
"tsdown-config-silverwind": "2.0.
|
|
28
|
+
"tsdown": "0.21.2",
|
|
29
|
+
"tsdown-config-silverwind": "2.0.1",
|
|
30
30
|
"typescript": "5.9.3",
|
|
31
31
|
"typescript-config-silverwind": "15.0.0",
|
|
32
|
-
"updates": "17.
|
|
32
|
+
"updates": "17.9.0",
|
|
33
33
|
"updates-config-silverwind": "1.0.3",
|
|
34
34
|
"versions": "14.2.1",
|
|
35
35
|
"vitest": "4.0.18",
|