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