cidr-tools 11.0.10 → 11.0.12
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.d.ts +26 -24
- package/dist/index.js +351 -332
- package/package.json +12 -11
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region index.d.ts
|
|
1
2
|
type IPv4Address = string;
|
|
2
3
|
type IPv6Address = string;
|
|
3
4
|
type IPv4CIDR = string;
|
|
@@ -6,38 +7,39 @@ type Network = IPv4Address | IPv4CIDR | IPv6Address | IPv6CIDR;
|
|
|
6
7
|
type Networks = Network | Array<Network>;
|
|
7
8
|
type ValidIpVersion = 4 | 6;
|
|
8
9
|
type ParsedCidr = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
cidr: string;
|
|
11
|
+
ip: string;
|
|
12
|
+
version: ValidIpVersion;
|
|
13
|
+
prefix: string;
|
|
14
|
+
prefixPresent: boolean;
|
|
15
|
+
start: bigint;
|
|
16
|
+
end: bigint;
|
|
16
17
|
};
|
|
17
18
|
type NormalizeOpts = {
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
compress?: boolean;
|
|
20
|
+
hexify?: boolean;
|
|
20
21
|
};
|
|
21
22
|
/** Returns a string or array (depending on input) with a normalized representation. Will not include a prefix on single IPs. Will set network address to the start of the network. */
|
|
22
|
-
|
|
23
|
+
declare function normalizeCidr<T extends Network | Array<Network>>(cidr: T, opts?: NormalizeOpts): T;
|
|
23
24
|
/** Returns a `parsed` Object which is used internally by this module. It can be used to test whether the passed network is IPv4 or IPv6 or to work with the BigInts directly. */
|
|
24
|
-
|
|
25
|
+
declare function parseCidr(str: Network): ParsedCidr;
|
|
25
26
|
/** Returns an array of merged networks */
|
|
26
|
-
|
|
27
|
+
declare function mergeCidr(nets: Networks): Array<Network>;
|
|
27
28
|
/** Returns an array of merged remaining networks of the subtraction of `excludeNetworks` from `baseNetworks`. */
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
declare function excludeCidr(base: Networks, excl: Networks): Array<Network>;
|
|
30
|
+
declare function expandCidr(nets: Networks): Generator<Network>;
|
|
30
31
|
/** Returns a boolean that indicates if `networksA` overlap (intersect) with `networksB`. */
|
|
31
|
-
|
|
32
|
+
declare function overlapCidr(a: Networks, b: Networks): boolean;
|
|
32
33
|
/** Returns a boolean that indicates whether `networksA` fully contain all `networksB`. */
|
|
33
|
-
|
|
34
|
+
declare function containsCidr(a: Networks, b: Networks): boolean;
|
|
34
35
|
declare const _default: {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
mergeCidr: typeof mergeCidr;
|
|
37
|
+
excludeCidr: typeof excludeCidr;
|
|
38
|
+
expandCidr: typeof expandCidr;
|
|
39
|
+
overlapCidr: typeof overlapCidr;
|
|
40
|
+
containsCidr: typeof containsCidr;
|
|
41
|
+
normalizeCidr: typeof normalizeCidr;
|
|
42
|
+
parseCidr: typeof parseCidr;
|
|
42
43
|
};
|
|
43
|
-
|
|
44
|
+
//#endregion
|
|
45
|
+
export { containsCidr, _default as default, excludeCidr, expandCidr, mergeCidr, normalizeCidr, overlapCidr, parseCidr };
|
package/dist/index.js
CHANGED
|
@@ -1,362 +1,381 @@
|
|
|
1
|
-
import { parseIp, stringifyIp
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { normalizeIp, parseIp, stringifyIp } from "ip-bigint";
|
|
2
|
+
|
|
3
|
+
//#region index.ts
|
|
4
|
+
const bits = {
|
|
5
|
+
4: 32,
|
|
6
|
+
6: 128
|
|
7
|
+
};
|
|
8
|
+
function parseIPv4Fast(s) {
|
|
9
|
+
let num = 0;
|
|
10
|
+
let octet = 0;
|
|
11
|
+
let dots = 0;
|
|
12
|
+
let digits = 0;
|
|
13
|
+
for (let i = 0; i < s.length; i++) {
|
|
14
|
+
const c = s.charCodeAt(i);
|
|
15
|
+
if (c === 46) {
|
|
16
|
+
if (digits === 0 || octet > 255) return -1;
|
|
17
|
+
num = (num << 8 | octet) >>> 0;
|
|
18
|
+
octet = 0;
|
|
19
|
+
dots++;
|
|
20
|
+
digits = 0;
|
|
21
|
+
} else if (c >= 48 && c <= 57) {
|
|
22
|
+
octet = octet * 10 + (c - 48);
|
|
23
|
+
digits++;
|
|
24
|
+
} else return -1;
|
|
25
|
+
}
|
|
26
|
+
if (dots !== 3 || digits === 0 || octet > 255) return -1;
|
|
27
|
+
return (num << 8 | octet) >>> 0;
|
|
28
|
+
}
|
|
29
|
+
function formatIPv4Fast(n) {
|
|
30
|
+
return `${n >>> 24 & 255}.${n >>> 16 & 255}.${n >>> 8 & 255}.${n & 255}`;
|
|
6
31
|
}
|
|
7
32
|
function doNormalize(cidr, { compress = true, hexify = false } = {}) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
33
|
+
const { start, end, prefix, version, prefixPresent } = parseCidr(cidr);
|
|
34
|
+
if (start !== end || prefixPresent) return `${normalizeIp(stringifyIp({
|
|
35
|
+
number: start,
|
|
36
|
+
version
|
|
37
|
+
}), {
|
|
38
|
+
compress,
|
|
39
|
+
hexify
|
|
40
|
+
})}/${prefix}`;
|
|
41
|
+
else return normalizeIp(cidr, {
|
|
42
|
+
compress,
|
|
43
|
+
hexify
|
|
44
|
+
});
|
|
15
45
|
}
|
|
46
|
+
/** Returns a string or array (depending on input) with a normalized representation. Will not include a prefix on single IPs. Will set network address to the start of the network. */
|
|
16
47
|
function normalizeCidr(cidr, opts) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} else {
|
|
20
|
-
return doNormalize(cidr, opts);
|
|
21
|
-
}
|
|
48
|
+
if (Array.isArray(cidr)) return cidr.map((entry) => normalizeCidr(entry, opts));
|
|
49
|
+
else return doNormalize(cidr, opts);
|
|
22
50
|
}
|
|
51
|
+
/** Returns a `parsed` Object which is used internally by this module. It can be used to test whether the passed network is IPv4 or IPv6 or to work with the BigInts directly. */
|
|
23
52
|
function parseCidr(str) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
parsed.end = number | mask;
|
|
56
|
-
return parsed;
|
|
53
|
+
const parsed = Object.create(null);
|
|
54
|
+
const slashIndex = str.indexOf("/");
|
|
55
|
+
let ipPart;
|
|
56
|
+
let prefix;
|
|
57
|
+
if (slashIndex !== -1) {
|
|
58
|
+
ipPart = str.substring(0, slashIndex);
|
|
59
|
+
prefix = str.substring(slashIndex + 1);
|
|
60
|
+
if (!/^[0-9]+$/.test(prefix)) throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
61
|
+
parsed.prefixPresent = true;
|
|
62
|
+
} else {
|
|
63
|
+
ipPart = str;
|
|
64
|
+
parsed.prefixPresent = false;
|
|
65
|
+
prefix = "";
|
|
66
|
+
}
|
|
67
|
+
const { number, version, ipv4mapped, scopeid } = parseIp(ipPart);
|
|
68
|
+
if (!version) throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
69
|
+
if (!parsed.prefixPresent) prefix = String(bits[version]);
|
|
70
|
+
parsed.version = version;
|
|
71
|
+
parsed.ip = stringifyIp({
|
|
72
|
+
number,
|
|
73
|
+
version,
|
|
74
|
+
ipv4mapped,
|
|
75
|
+
scopeid
|
|
76
|
+
});
|
|
77
|
+
parsed.cidr = `${parsed.ip}/${prefix}`;
|
|
78
|
+
parsed.prefix = prefix;
|
|
79
|
+
const hostBits = bits[version] - Number(prefix);
|
|
80
|
+
const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
|
|
81
|
+
parsed.start = number & ~mask;
|
|
82
|
+
parsed.end = number | mask;
|
|
83
|
+
return parsed;
|
|
57
84
|
}
|
|
58
85
|
function parseCidrLean(str) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
if (a.start > b.start && a.end < b.end) {
|
|
97
|
-
return [];
|
|
98
|
-
}
|
|
99
|
-
const parts = [];
|
|
100
|
-
if (a.start < b.start && a.end <= b.end) {
|
|
101
|
-
parts.push({ start: a.start, end: b.start - 1n });
|
|
102
|
-
}
|
|
103
|
-
if (a.start >= b.start && a.end > b.end) {
|
|
104
|
-
parts.push({ start: b.end + 1n, end: a.end });
|
|
105
|
-
}
|
|
106
|
-
if (a.start < b.start && a.end > b.end) {
|
|
107
|
-
parts.push(
|
|
108
|
-
{ start: a.start, end: b.start - 1n },
|
|
109
|
-
{ start: b.end + 1n, end: a.end }
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
const remaining = [];
|
|
113
|
-
for (const part of parts) {
|
|
114
|
-
subparts(part, remaining);
|
|
115
|
-
}
|
|
116
|
-
return remaining;
|
|
86
|
+
const slashIndex = str.indexOf("/");
|
|
87
|
+
let ipPart;
|
|
88
|
+
let prefixNum;
|
|
89
|
+
if (slashIndex !== -1) {
|
|
90
|
+
ipPart = str.substring(0, slashIndex);
|
|
91
|
+
const prefixStr = str.substring(slashIndex + 1);
|
|
92
|
+
if (!/^[0-9]+$/.test(prefixStr)) throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
93
|
+
prefixNum = Number(prefixStr);
|
|
94
|
+
} else {
|
|
95
|
+
ipPart = str;
|
|
96
|
+
prefixNum = -1;
|
|
97
|
+
}
|
|
98
|
+
if (!ipPart.includes(":")) {
|
|
99
|
+
const v4num = parseIPv4Fast(ipPart);
|
|
100
|
+
if (v4num !== -1) {
|
|
101
|
+
if (prefixNum === -1) prefixNum = 32;
|
|
102
|
+
const bigNum = BigInt(v4num);
|
|
103
|
+
const hostBits = 32 - prefixNum;
|
|
104
|
+
const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
|
|
105
|
+
return {
|
|
106
|
+
start: bigNum & ~mask,
|
|
107
|
+
end: bigNum | mask,
|
|
108
|
+
version: 4
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const { number, version } = parseIp(ipPart);
|
|
113
|
+
if (!version) throw new Error(`Network is not a CIDR or IP: "${str}"`);
|
|
114
|
+
if (prefixNum === -1) prefixNum = bits[version];
|
|
115
|
+
const hostBits = bits[version] - prefixNum;
|
|
116
|
+
const mask = hostBits > 0 ? (1n << BigInt(hostBits)) - 1n : 0n;
|
|
117
|
+
return {
|
|
118
|
+
start: number & ~mask,
|
|
119
|
+
end: number | mask,
|
|
120
|
+
version
|
|
121
|
+
};
|
|
117
122
|
}
|
|
118
123
|
function biggestPowerOfTwo(num) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
let n = num >> 1n;
|
|
122
|
-
while (n > 0n) {
|
|
123
|
-
b++;
|
|
124
|
-
n >>= 1n;
|
|
125
|
-
}
|
|
126
|
-
return 1n << b;
|
|
124
|
+
if (num === 0n) return 0n;
|
|
125
|
+
return 1n << BigInt(num.toString(2).length - 1);
|
|
127
126
|
}
|
|
128
127
|
function subparts(part, output) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
128
|
+
if (!output) output = [];
|
|
129
|
+
if (part.end < part.start) return output;
|
|
130
|
+
if (part.end === part.start) {
|
|
131
|
+
output.push(part);
|
|
132
|
+
return output;
|
|
133
|
+
}
|
|
134
|
+
if (part.end - part.start === 1n) {
|
|
135
|
+
if (part.end % 2n === 0n) output.push({
|
|
136
|
+
start: part.start,
|
|
137
|
+
end: part.start
|
|
138
|
+
}, {
|
|
139
|
+
start: part.end,
|
|
140
|
+
end: part.end
|
|
141
|
+
});
|
|
142
|
+
else output.push({
|
|
143
|
+
start: part.start,
|
|
144
|
+
end: part.end
|
|
145
|
+
});
|
|
146
|
+
return output;
|
|
147
|
+
}
|
|
148
|
+
const size = diff(part.end, part.start);
|
|
149
|
+
let biggest = biggestPowerOfTwo(size);
|
|
150
|
+
let start;
|
|
151
|
+
let end;
|
|
152
|
+
if (size === biggest && part.start % biggest === 0n) {
|
|
153
|
+
output.push(part);
|
|
154
|
+
return output;
|
|
155
|
+
} else if (part.start % biggest === 0n) {
|
|
156
|
+
start = part.start;
|
|
157
|
+
end = start + biggest - 1n;
|
|
158
|
+
} else {
|
|
159
|
+
start = part.end / biggest * biggest;
|
|
160
|
+
if (start + biggest - 1n > part.end) {
|
|
161
|
+
start = (part.end / biggest - 1n) * biggest;
|
|
162
|
+
while (start < part.start) {
|
|
163
|
+
biggest /= 2n;
|
|
164
|
+
start = (part.end / biggest - 1n) * biggest;
|
|
165
|
+
}
|
|
166
|
+
end = start + biggest - 1n;
|
|
167
|
+
} else {
|
|
168
|
+
start = part.end / biggest * biggest;
|
|
169
|
+
end = start + biggest - 1n;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (start !== part.start) subparts({
|
|
173
|
+
start: part.start,
|
|
174
|
+
end: start - 1n
|
|
175
|
+
}, output);
|
|
176
|
+
output.push({
|
|
177
|
+
start,
|
|
178
|
+
end
|
|
179
|
+
});
|
|
180
|
+
if (end !== part.end) subparts({
|
|
181
|
+
start: end + 1n,
|
|
182
|
+
end: part.end
|
|
183
|
+
}, output);
|
|
184
|
+
return output;
|
|
177
185
|
}
|
|
178
186
|
function diff(a, b) {
|
|
179
|
-
|
|
187
|
+
return a + 1n - b;
|
|
180
188
|
}
|
|
181
189
|
function formatPart(part, version) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
if (version === 4) {
|
|
191
|
+
const ip = formatIPv4Fast(Number(part.start));
|
|
192
|
+
const sizeNum = Number(part.end - part.start) + 1;
|
|
193
|
+
return `${ip}/${32 - (sizeNum <= 1 ? 0 : sizeNum >= 4294967296 ? 32 : 31 - Math.clz32(sizeNum))}`;
|
|
194
|
+
}
|
|
195
|
+
const ip = stringifyIp({
|
|
196
|
+
number: part.start,
|
|
197
|
+
version
|
|
198
|
+
});
|
|
199
|
+
const size = diff(part.end, part.start);
|
|
200
|
+
const hostBits = size <= 1n ? 0 : size.toString(2).length - 1;
|
|
201
|
+
return `${ip}/${bits[version] - hostBits}`;
|
|
192
202
|
}
|
|
193
|
-
function
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
203
|
+
function mergeIntervalsRaw(nets) {
|
|
204
|
+
if (nets.length === 0) return [];
|
|
205
|
+
const sorted = nets.slice().sort((a, b) => a.start > b.start ? 1 : a.start < b.start ? -1 : a.end > b.end ? 1 : a.end < b.end ? -1 : 0);
|
|
206
|
+
const merged = [];
|
|
207
|
+
let curStart = sorted[0].start;
|
|
208
|
+
let curEnd = sorted[0].end;
|
|
209
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
210
|
+
const { start, end } = sorted[i];
|
|
211
|
+
if (start <= curEnd + 1n) {
|
|
212
|
+
if (end > curEnd) curEnd = end;
|
|
213
|
+
} else {
|
|
214
|
+
merged.push({
|
|
215
|
+
start: curStart,
|
|
216
|
+
end: curEnd
|
|
217
|
+
});
|
|
218
|
+
curStart = start;
|
|
219
|
+
curEnd = end;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
merged.push({
|
|
223
|
+
start: curStart,
|
|
224
|
+
end: curEnd
|
|
225
|
+
});
|
|
226
|
+
return merged;
|
|
210
227
|
}
|
|
211
|
-
function
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
let depth = 0;
|
|
216
|
-
const merged = [];
|
|
217
|
-
for (const [index2, number] of numbers.entries()) {
|
|
218
|
-
const marker = maps.get(number);
|
|
219
|
-
if (start === null && marker.start) start = number;
|
|
220
|
-
if (marker.end) end = number;
|
|
221
|
-
if (start === null) continue;
|
|
222
|
-
if (marker.start) depth += marker.start;
|
|
223
|
-
if (marker.end) depth -= marker.end;
|
|
224
|
-
const next = numbers[index2 + 1];
|
|
225
|
-
if (marker.end && depth === 0 && next !== void 0 && next - number > 1n) {
|
|
226
|
-
subparts({ start, end }, merged);
|
|
227
|
-
start = null;
|
|
228
|
-
end = null;
|
|
229
|
-
} else if (index2 === numbers.length - 1) {
|
|
230
|
-
subparts({ start, end }, merged);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return merged;
|
|
228
|
+
function mergeIntervals(nets) {
|
|
229
|
+
const merged = [];
|
|
230
|
+
for (const part of mergeIntervalsRaw(nets)) subparts(part, merged);
|
|
231
|
+
return merged;
|
|
234
232
|
}
|
|
233
|
+
function subtractSorted(bases, excls) {
|
|
234
|
+
if (excls.length === 0) return bases;
|
|
235
|
+
if (bases.length === 0) return [];
|
|
236
|
+
const result = [];
|
|
237
|
+
let j = 0;
|
|
238
|
+
for (const base of bases) {
|
|
239
|
+
let start = base.start;
|
|
240
|
+
const end = base.end;
|
|
241
|
+
while (j < excls.length && excls[j].end < start) j++;
|
|
242
|
+
let k = j;
|
|
243
|
+
while (k < excls.length && excls[k].start <= end && start <= end) {
|
|
244
|
+
if (excls[k].start > start) result.push({
|
|
245
|
+
start,
|
|
246
|
+
end: excls[k].start - 1n
|
|
247
|
+
});
|
|
248
|
+
start = excls[k].end + 1n;
|
|
249
|
+
k++;
|
|
250
|
+
}
|
|
251
|
+
if (start <= end) result.push({
|
|
252
|
+
start,
|
|
253
|
+
end
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return result;
|
|
257
|
+
}
|
|
258
|
+
/** Returns an array of merged networks */
|
|
235
259
|
function mergeCidr(nets) {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
260
|
+
const arr = (Array.isArray(nets) ? nets : [nets]).map(parseCidrLean);
|
|
261
|
+
const byVersion = {
|
|
262
|
+
4: [],
|
|
263
|
+
6: []
|
|
264
|
+
};
|
|
265
|
+
for (const n of arr) byVersion[n.version].push(n);
|
|
266
|
+
const merged = [];
|
|
267
|
+
for (const v of [4, 6]) for (const part of mergeIntervals(byVersion[v])) merged.push(formatPart(part, v));
|
|
268
|
+
return merged;
|
|
245
269
|
}
|
|
270
|
+
/** Returns an array of merged remaining networks of the subtraction of `excludeNetworks` from `baseNetworks`. */
|
|
246
271
|
function excludeCidr(base, excl) {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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;
|
|
272
|
+
const baseArr = (Array.isArray(base) ? base : [base]).map(parseCidrLean);
|
|
273
|
+
const exclArr = (Array.isArray(excl) ? excl : [excl]).map(parseCidrLean);
|
|
274
|
+
const baseByVersion = {
|
|
275
|
+
4: [],
|
|
276
|
+
6: []
|
|
277
|
+
};
|
|
278
|
+
const exclByVersion = {
|
|
279
|
+
4: [],
|
|
280
|
+
6: []
|
|
281
|
+
};
|
|
282
|
+
for (const n of baseArr) baseByVersion[n.version].push(n);
|
|
283
|
+
for (const n of exclArr) exclByVersion[n.version].push(n);
|
|
284
|
+
const result = [];
|
|
285
|
+
for (const v of [4, 6]) {
|
|
286
|
+
const remaining = subtractSorted(mergeIntervalsRaw(baseByVersion[v]), mergeIntervalsRaw(exclByVersion[v]));
|
|
287
|
+
for (const part of remaining) {
|
|
288
|
+
const aligned = subparts(part);
|
|
289
|
+
for (const p of aligned) result.push(formatPart(p, v));
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return result;
|
|
275
293
|
}
|
|
276
294
|
function* expandCidr(nets) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
295
|
+
const arr = Array.isArray(nets) ? nets : [nets];
|
|
296
|
+
for (const net of mergeCidr(arr)) {
|
|
297
|
+
const { start, end, version } = parseCidrLean(net);
|
|
298
|
+
for (let number = start; number <= end; number++) yield normalizeIp(stringifyIp({
|
|
299
|
+
number,
|
|
300
|
+
version
|
|
301
|
+
}));
|
|
302
|
+
}
|
|
284
303
|
}
|
|
304
|
+
/** Returns a boolean that indicates if `networksA` overlap (intersect) with `networksB`. */
|
|
285
305
|
function overlapCidr(a, b) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
306
|
+
const aNets = (Array.isArray(a) ? a : [a]).map(parseCidrLean);
|
|
307
|
+
const bNets = (Array.isArray(b) ? b : [b]).map(parseCidrLean);
|
|
308
|
+
const aByVersion = {
|
|
309
|
+
4: [],
|
|
310
|
+
6: []
|
|
311
|
+
};
|
|
312
|
+
const bByVersion = {
|
|
313
|
+
4: [],
|
|
314
|
+
6: []
|
|
315
|
+
};
|
|
316
|
+
for (const n of aNets) aByVersion[n.version].push(n);
|
|
317
|
+
for (const n of bNets) bByVersion[n.version].push(n);
|
|
318
|
+
for (const v of [4, 6]) {
|
|
319
|
+
const aVer = aByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
|
|
320
|
+
const bVer = bByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
|
|
321
|
+
let i = 0, j = 0;
|
|
322
|
+
while (i < aVer.length && j < bVer.length) {
|
|
323
|
+
const aNet = aVer[i];
|
|
324
|
+
const bNet = bVer[j];
|
|
325
|
+
if (aNet.start <= bNet.end && bNet.start <= aNet.end) return true;
|
|
326
|
+
if (aNet.end < bNet.end) i++;
|
|
327
|
+
else j++;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return false;
|
|
305
331
|
}
|
|
332
|
+
/** Returns a boolean that indicates whether `networksA` fully contain all `networksB`. */
|
|
306
333
|
function containsCidr(a, b) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
return true;
|
|
334
|
+
const aNets = (Array.isArray(a) ? a : [a]).map(parseCidrLean);
|
|
335
|
+
const bNets = (Array.isArray(b) ? b : [b]).map(parseCidrLean);
|
|
336
|
+
const aByVersion = {
|
|
337
|
+
4: [],
|
|
338
|
+
6: []
|
|
339
|
+
};
|
|
340
|
+
const bByVersion = {
|
|
341
|
+
4: [],
|
|
342
|
+
6: []
|
|
343
|
+
};
|
|
344
|
+
for (const n of aNets) aByVersion[n.version].push(n);
|
|
345
|
+
for (const n of bNets) bByVersion[n.version].push(n);
|
|
346
|
+
for (const v of [4, 6]) {
|
|
347
|
+
const containers = aByVersion[v].sort((x, y) => x.start > y.start ? 1 : x.start < y.start ? -1 : 0);
|
|
348
|
+
const targets = bByVersion[v];
|
|
349
|
+
if (targets.length === 0) continue;
|
|
350
|
+
if (containers.length === 0) return false;
|
|
351
|
+
const maxEnd = new Array(containers.length);
|
|
352
|
+
maxEnd[0] = containers[0].end;
|
|
353
|
+
for (let i = 1; i < containers.length; i++) if (containers[i].end > maxEnd[i - 1]) maxEnd[i] = containers[i].end;
|
|
354
|
+
else maxEnd[i] = maxEnd[i - 1];
|
|
355
|
+
for (const target of targets) {
|
|
356
|
+
let lo = 0, hi = containers.length - 1;
|
|
357
|
+
let idx = -1;
|
|
358
|
+
while (lo <= hi) {
|
|
359
|
+
const mid = lo + hi >> 1;
|
|
360
|
+
if (containers[mid].start <= target.start) {
|
|
361
|
+
idx = mid;
|
|
362
|
+
lo = mid + 1;
|
|
363
|
+
} else hi = mid - 1;
|
|
364
|
+
}
|
|
365
|
+
if (idx < 0 || maxEnd[idx] < target.end) return false;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return true;
|
|
343
369
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
};
|
|
353
|
-
export {
|
|
354
|
-
containsCidr,
|
|
355
|
-
index as default,
|
|
356
|
-
excludeCidr,
|
|
357
|
-
expandCidr,
|
|
358
|
-
mergeCidr,
|
|
359
|
-
normalizeCidr,
|
|
360
|
-
overlapCidr,
|
|
361
|
-
parseCidr
|
|
370
|
+
var cidr_tools_default = {
|
|
371
|
+
mergeCidr,
|
|
372
|
+
excludeCidr,
|
|
373
|
+
expandCidr,
|
|
374
|
+
overlapCidr,
|
|
375
|
+
containsCidr,
|
|
376
|
+
normalizeCidr,
|
|
377
|
+
parseCidr
|
|
362
378
|
};
|
|
379
|
+
|
|
380
|
+
//#endregion
|
|
381
|
+
export { containsCidr, cidr_tools_default as default, excludeCidr, expandCidr, mergeCidr, normalizeCidr, overlapCidr, parseCidr };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cidr-tools",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.12",
|
|
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,21 +17,22 @@
|
|
|
17
17
|
"node": ">=18"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"ip-bigint": "^8.2.
|
|
20
|
+
"ip-bigint": "^8.2.8"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@
|
|
24
|
-
"
|
|
25
|
-
"eslint
|
|
23
|
+
"@types/node": "25.3.3",
|
|
24
|
+
"@typescript/native-preview": "7.0.0-dev.20260305.1",
|
|
25
|
+
"eslint": "9.39.3",
|
|
26
|
+
"eslint-config-silverwind": "121.2.0",
|
|
26
27
|
"jest-extended": "7.0.0",
|
|
28
|
+
"tsdown": "0.21.0",
|
|
29
|
+
"tsdown-config-silverwind": "2.0.0",
|
|
27
30
|
"typescript": "5.9.3",
|
|
28
|
-
"typescript-config-silverwind": "
|
|
29
|
-
"updates": "17.1
|
|
31
|
+
"typescript-config-silverwind": "15.0.0",
|
|
32
|
+
"updates": "17.8.1",
|
|
30
33
|
"updates-config-silverwind": "1.0.3",
|
|
31
|
-
"versions": "14.1
|
|
32
|
-
"vite": "7.3.1",
|
|
33
|
-
"vite-config-silverwind": "6.0.9",
|
|
34
|
+
"versions": "14.2.1",
|
|
34
35
|
"vitest": "4.0.18",
|
|
35
|
-
"vitest-config-silverwind": "10.6.
|
|
36
|
+
"vitest-config-silverwind": "10.6.3"
|
|
36
37
|
}
|
|
37
38
|
}
|