pmcf 2.15.1 → 2.16.0
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/package.json +1 -1
- package/src/cli.mjs +8 -3
- package/src/dns-utils.mjs +4 -28
- package/src/host-utils.mjs +1 -9
- package/src/host.mjs +10 -12
- package/src/ip.mjs +298 -0
- package/src/owner.mjs +2 -2
- package/src/service.mjs +2 -1
- package/src/services/dhcp.mjs +7 -6
- package/src/services/dns.mjs +11 -14
- package/src/subnet.mjs +9 -27
- package/src/utils.mjs +0 -202
- package/types/dns-utils.d.mts +0 -2
- package/types/ip.d.mts +36 -0
- package/types/subnet.d.mts +3 -3
- package/types/utils.d.mts +0 -29
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { parseArgs } from "node:util";
|
|
2
|
+
import { resolve } from "node:path";
|
|
2
3
|
import { argv, cwd, env } from "node:process";
|
|
3
4
|
import { Root } from "./module.mjs";
|
|
4
5
|
|
|
5
|
-
export async function prepare(options={}) {
|
|
6
|
+
export async function prepare(options = {}) {
|
|
6
7
|
const { values, positionals } = parseArgs({
|
|
7
8
|
args: argv.slice(2),
|
|
8
9
|
options: {
|
|
@@ -17,7 +18,7 @@ export async function prepare(options={}) {
|
|
|
17
18
|
default: false
|
|
18
19
|
},
|
|
19
20
|
publish: {
|
|
20
|
-
type: "string"
|
|
21
|
+
type: "string"
|
|
21
22
|
},
|
|
22
23
|
root: {
|
|
23
24
|
type: "string",
|
|
@@ -32,9 +33,13 @@ export async function prepare(options={}) {
|
|
|
32
33
|
allowPositionals: true
|
|
33
34
|
});
|
|
34
35
|
|
|
36
|
+
if (values.output) {
|
|
37
|
+
values.output = resolve(cwd(), values.output);
|
|
38
|
+
}
|
|
39
|
+
|
|
35
40
|
const root = new Root(values.root);
|
|
36
41
|
|
|
37
42
|
await root.loadAll();
|
|
38
|
-
|
|
43
|
+
|
|
39
44
|
return { root, options: values, args: positionals };
|
|
40
45
|
}
|
package/src/dns-utils.mjs
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
decodeIPv6,
|
|
4
|
-
encodeIPv6,
|
|
5
|
-
isIPv6Address,
|
|
6
|
-
normalizeIPAddress
|
|
7
|
-
} from "./utils.mjs";
|
|
1
|
+
import { asIterator } from "./utils.mjs";
|
|
2
|
+
import { decodeIPv4, decodeIPv6 } from "./ip.mjs";
|
|
8
3
|
|
|
9
4
|
export function dnsFullName(name) {
|
|
10
5
|
return name.endsWith(".") ? name : name + ".";
|
|
@@ -19,10 +14,10 @@ export function DNSRecord(key, type, ...values) {
|
|
|
19
14
|
break;
|
|
20
15
|
|
|
21
16
|
case "A":
|
|
22
|
-
values[0] =
|
|
17
|
+
values[0] = decodeIPv4(values[0]);
|
|
23
18
|
break;
|
|
24
19
|
case "AAAA":
|
|
25
|
-
values[0] = decodeIPv6(
|
|
20
|
+
values[0] = decodeIPv6(values[0]);
|
|
26
21
|
break;
|
|
27
22
|
}
|
|
28
23
|
|
|
@@ -59,22 +54,3 @@ export function dnsMergeParameters(a, b) {
|
|
|
59
54
|
])
|
|
60
55
|
);
|
|
61
56
|
}
|
|
62
|
-
|
|
63
|
-
export function reverseAddress(address) {
|
|
64
|
-
if (isIPv6Address(address)) {
|
|
65
|
-
return normalizeIPAddress(address)
|
|
66
|
-
.replaceAll(":", "")
|
|
67
|
-
.split("")
|
|
68
|
-
.reverse()
|
|
69
|
-
.join(".");
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return address.split(".").reverse().join(".");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function reverseArpaAddress(address) {
|
|
76
|
-
return (
|
|
77
|
-
reverseAddress(address) +
|
|
78
|
-
(isIPv6Address(address) ? ".ip6.arpa" : ".in-addr.arpa")
|
|
79
|
-
);
|
|
80
|
-
}
|
package/src/host-utils.mjs
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
writeFile,
|
|
3
|
-
mkdir,
|
|
4
|
-
copyFile,
|
|
5
|
-
glob,
|
|
6
|
-
chmod,
|
|
7
|
-
stat
|
|
8
|
-
} from "node:fs/promises";
|
|
1
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
9
2
|
import { join } from "node:path";
|
|
10
|
-
import { FileContentProvider } from "npm-pkgbuild";
|
|
11
3
|
import { writeLines, sectionLines } from "../src/utils.mjs";
|
|
12
4
|
import { addHook } from "./hooks.mjs";
|
|
13
5
|
|
package/src/host.mjs
CHANGED
|
@@ -6,16 +6,14 @@ import {
|
|
|
6
6
|
networkProperties,
|
|
7
7
|
networkAddressProperties
|
|
8
8
|
} from "./network-support.mjs";
|
|
9
|
+
import { asArray, domainFromDominName, domainName } from "./utils.mjs";
|
|
9
10
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
isIPv6Address,
|
|
13
|
-
normalizeIPAddress,
|
|
11
|
+
isIPv4,
|
|
12
|
+
isIPv6,
|
|
14
13
|
formatCIDR,
|
|
15
14
|
hasWellKnownSubnet,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
} from "./utils.mjs";
|
|
15
|
+
normalizeIP
|
|
16
|
+
} from "./ip.mjs";
|
|
19
17
|
import { objectFilter } from "./filter.mjs";
|
|
20
18
|
import { addType, types } from "./types.mjs";
|
|
21
19
|
import { loadHooks } from "./hooks.mjs";
|
|
@@ -582,7 +580,7 @@ export class NetworkInterface extends Base {
|
|
|
582
580
|
set ipAddresses(value) {
|
|
583
581
|
for (const address of asArray(value)) {
|
|
584
582
|
this._ipAddresses.set(
|
|
585
|
-
|
|
583
|
+
normalizeIP(address),
|
|
586
584
|
this.addSubnet(address)
|
|
587
585
|
);
|
|
588
586
|
}
|
|
@@ -593,11 +591,11 @@ export class NetworkInterface extends Base {
|
|
|
593
591
|
}
|
|
594
592
|
|
|
595
593
|
get rawIPv4Address() {
|
|
596
|
-
return this.rawAddresses.filter(a =>
|
|
594
|
+
return this.rawAddresses.filter(a => isIPv4(a))[0];
|
|
597
595
|
}
|
|
598
596
|
|
|
599
597
|
get rawIPv6Address() {
|
|
600
|
-
return this.rawAddresses.filter(a =>
|
|
598
|
+
return this.rawAddresses.filter(a => isIPv6(a))[0];
|
|
601
599
|
}
|
|
602
600
|
|
|
603
601
|
get rawAddresses() {
|
|
@@ -616,13 +614,13 @@ export class NetworkInterface extends Base {
|
|
|
616
614
|
|
|
617
615
|
get rawIPv4Addresses() {
|
|
618
616
|
return [...this.ipAddresses]
|
|
619
|
-
.filter(([address]) =>
|
|
617
|
+
.filter(([address]) => isIPv4(address))
|
|
620
618
|
.map(([address]) => address);
|
|
621
619
|
}
|
|
622
620
|
|
|
623
621
|
get rawIPv6Addresses() {
|
|
624
622
|
return [...this.ipAddresses]
|
|
625
|
-
.filter(([address]) =>
|
|
623
|
+
.filter(([address]) => isIPv6(address))
|
|
626
624
|
.map(([address]) => address);
|
|
627
625
|
}
|
|
628
626
|
|
package/src/ip.mjs
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
const ipv4 = {
|
|
2
|
+
factory: Uint8Array,
|
|
3
|
+
normalize(address) {
|
|
4
|
+
return address;
|
|
5
|
+
},
|
|
6
|
+
separator: ".",
|
|
7
|
+
bitLength: 32,
|
|
8
|
+
byteLength: 4,
|
|
9
|
+
segments: 4,
|
|
10
|
+
segmentLength: 8,
|
|
11
|
+
segmentMask: 0xffn,
|
|
12
|
+
mask: 0xffffffffn,
|
|
13
|
+
base: 10
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const ipv6 = {
|
|
17
|
+
factory: Uint16Array,
|
|
18
|
+
normalize(address) {
|
|
19
|
+
const parts = address.split(":");
|
|
20
|
+
const i = parts.indexOf("");
|
|
21
|
+
if (i >= 0) {
|
|
22
|
+
parts.splice(i, 1, ..."0".repeat(9 - parts.length));
|
|
23
|
+
}
|
|
24
|
+
return parts /*.map(s => s.padStart(4, "0"))*/
|
|
25
|
+
.join(":");
|
|
26
|
+
},
|
|
27
|
+
separator: ":",
|
|
28
|
+
compressor: "::",
|
|
29
|
+
bitLength: 128,
|
|
30
|
+
byteLength: 8,
|
|
31
|
+
segments: 8,
|
|
32
|
+
segmentLength: 16,
|
|
33
|
+
segmentMask: 0xffffn,
|
|
34
|
+
mask: 0xffffffffffffffffffffffffffffffffn,
|
|
35
|
+
base: 16
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function IPV4(...args) {
|
|
39
|
+
return _create(ipv4, ...args);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function IPV6(...args) {
|
|
43
|
+
return _create(ipv6, ...args);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function _create(definition, ...args) {
|
|
47
|
+
if (args.length === 1) {
|
|
48
|
+
return _encode(definition, args[0]);
|
|
49
|
+
}
|
|
50
|
+
return new definition.factory(args);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function encodeIP(address) {
|
|
54
|
+
return _encode(isIPv4(address) ? ipv4 : ipv6, address);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function encodeIPv6(address) {
|
|
58
|
+
return _encode(ipv6, address);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function encodeIPv4(address) {
|
|
62
|
+
return _encode(ipv4, address);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function _encode(definition, address) {
|
|
66
|
+
switch (typeof address) {
|
|
67
|
+
case "string":
|
|
68
|
+
const res = new definition.factory(definition.segments);
|
|
69
|
+
|
|
70
|
+
let i = 0;
|
|
71
|
+
for (const segment of definition
|
|
72
|
+
.normalize(address)
|
|
73
|
+
.split(definition.separator)) {
|
|
74
|
+
res[i++] = parseInt(segment, definition.base);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return res;
|
|
78
|
+
|
|
79
|
+
case "object":
|
|
80
|
+
if (
|
|
81
|
+
address instanceof definition.factory &&
|
|
82
|
+
address.length === definition.byteLength
|
|
83
|
+
) {
|
|
84
|
+
return address;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function _decode(definition, address, length) {
|
|
90
|
+
switch (typeof address) {
|
|
91
|
+
case "string":
|
|
92
|
+
if (length === undefined) {
|
|
93
|
+
return address;
|
|
94
|
+
}
|
|
95
|
+
address = _encode(definition, address);
|
|
96
|
+
break;
|
|
97
|
+
case "bigint":
|
|
98
|
+
address = _encodeBigInt(definition, address);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let result = "";
|
|
102
|
+
let compressed = 0;
|
|
103
|
+
let word;
|
|
104
|
+
let last = address?.length;
|
|
105
|
+
|
|
106
|
+
if (length !== undefined) {
|
|
107
|
+
length /= definition.segmentLength;
|
|
108
|
+
|
|
109
|
+
if (length < last) {
|
|
110
|
+
last = length;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
for (let i = 0, j = 0; i < last; j = j + 1, i = j) {
|
|
114
|
+
for (; j < last; j++) {
|
|
115
|
+
word = address[j];
|
|
116
|
+
|
|
117
|
+
if (word !== 0 || !definition.compressor || compressed > 0) {
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (j > i + 1) {
|
|
123
|
+
compressed++;
|
|
124
|
+
result += definition.compressor;
|
|
125
|
+
} else {
|
|
126
|
+
if (result.length > 0) {
|
|
127
|
+
result += definition.separator;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (j < last) {
|
|
132
|
+
result += word.toString(definition.base);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export function decodeIPv6(address, length) {
|
|
140
|
+
return _decode(ipv6, address, length);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function decodeIPv4(address, length) {
|
|
144
|
+
return _decode(ipv4, address, length);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function decodeIP(address, length) {
|
|
148
|
+
return _decode(isIPv4(address) ? ipv4 : ipv6, address, length);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function isIPv4(address) {
|
|
152
|
+
return _is(ipv4, address);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function isIPv6(address) {
|
|
156
|
+
return _is(ipv6, address);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function _is(definition, address) {
|
|
160
|
+
switch (typeof address) {
|
|
161
|
+
case "string":
|
|
162
|
+
return address.indexOf(definition.separator) >= 0;
|
|
163
|
+
|
|
164
|
+
case "object":
|
|
165
|
+
return (
|
|
166
|
+
address instanceof definition.factory &&
|
|
167
|
+
address.length === definition.byteLength
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function asBigInt(address) {
|
|
175
|
+
return _asBigInt(isIPv4(address) ? ipv4 : ipv6, address);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function _asBigInt(definition, address) {
|
|
179
|
+
if (typeof address === "bigint") {
|
|
180
|
+
return address;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const ea = _encode(definition, address);
|
|
184
|
+
|
|
185
|
+
let result = 0n;
|
|
186
|
+
|
|
187
|
+
for (let i = 0; i < ea.length; i++) {
|
|
188
|
+
result = result << BigInt(definition.segmentLength);
|
|
189
|
+
result += BigInt(ea[i]);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function _encodeBigInt(definition, address) {
|
|
196
|
+
const segments = [];
|
|
197
|
+
|
|
198
|
+
for (let i = 0; i < definition.segments; i++) {
|
|
199
|
+
segments.push(Number(address & definition.segmentMask));
|
|
200
|
+
address >>= BigInt(definition.segmentLength);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return new definition.factory(segments.reverse());
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function prefixIP(address, length) {
|
|
207
|
+
const definition = isIPv4(address) ? ipv4 : ipv6;
|
|
208
|
+
return _decode(definition, _prefix(definition, address, length));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function _prefix(definition, address, length) {
|
|
212
|
+
return (
|
|
213
|
+
_asBigInt(definition, address) &
|
|
214
|
+
(definition.mask << BigInt(definition.bitLength - length))
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function normalizeCIDR(address) {
|
|
219
|
+
let [prefix, prefixLength] = address.split(/\//);
|
|
220
|
+
let longPrefix;
|
|
221
|
+
|
|
222
|
+
if (!prefixLength && isLinkLocal(address)) {
|
|
223
|
+
prefix = "fe80::";
|
|
224
|
+
longPrefix = prefix;
|
|
225
|
+
prefixLength = 64;
|
|
226
|
+
} else {
|
|
227
|
+
prefixLength = parseInt(prefixLength);
|
|
228
|
+
|
|
229
|
+
const definition = isIPv6(prefix) ? ipv6 : ipv4;
|
|
230
|
+
let n;
|
|
231
|
+
|
|
232
|
+
if (prefixLength) {
|
|
233
|
+
n = _prefix(definition, prefix, prefixLength);
|
|
234
|
+
} else {
|
|
235
|
+
n = _encode(definition, prefix);
|
|
236
|
+
|
|
237
|
+
if (isLocalhost(n)) {
|
|
238
|
+
prefixLength = definition === ipv6 ? 128 : 8;
|
|
239
|
+
} else {
|
|
240
|
+
return {};
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
prefix = _decode(definition, n, prefixLength);
|
|
244
|
+
longPrefix = _decode(definition, n);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return { longPrefix, prefix, prefixLength, cidr: `${prefix}/${prefixLength}` };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function formatCIDR(address, subnet) {
|
|
251
|
+
return subnet ? `${address}/${subnet.prefixLength}` : address;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function normalizeIP(address) {
|
|
255
|
+
return decodeIP(encodeIP(address));
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export function reverseArpa(address) {
|
|
259
|
+
if (isIPv6(address)) {
|
|
260
|
+
const ea = encodeIPv6(address);
|
|
261
|
+
let result = [];
|
|
262
|
+
for (let i = 0; i < ea.length; i++) {
|
|
263
|
+
const v = ea[i];
|
|
264
|
+
for (let i = 0; i < 4; i++) {
|
|
265
|
+
result.push(((v >> (12 - 4 * i)) & 0x000f).toString(16));
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return result.reverse().join(".") + ".ip6.arpa";
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return address.split(".").reverse().join(".") + ".in-addr.arpa";
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export function isLocalhost(address) {
|
|
275
|
+
const eaddr = encodeIP(address);
|
|
276
|
+
|
|
277
|
+
if (!eaddr) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const str = eaddr.toString();
|
|
282
|
+
|
|
283
|
+
return str === IPV4_LOCALHOST.toString() || str === IPV6_LOCALHOST.toString();
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export function isLinkLocal(address) {
|
|
287
|
+
const eaddr = encodeIP(address);
|
|
288
|
+
return eaddr[0] === 0xfe80;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export function hasWellKnownSubnet(address) {
|
|
292
|
+
return isLocalhost(address) || isLinkLocal(address);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export const IPV6_LINK_LOCAL_BROADCAST = _encode(ipv6, "ff02::1");
|
|
296
|
+
export const IPV6_ROUTER_BROADCAST = _encode(ipv6, "ff02::2");
|
|
297
|
+
export const IPV4_LOCALHOST = _encode(ipv4, "127.0.0.1");
|
|
298
|
+
export const IPV6_LOCALHOST = _encode(ipv6, "::1");
|
package/src/owner.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { asIterator
|
|
1
|
+
import { asIterator } from "./utils.mjs";
|
|
2
2
|
import { Base } from "./base.mjs";
|
|
3
3
|
import { Subnet } from "./subnet.mjs";
|
|
4
4
|
import { addType, types } from "./types.mjs";
|
|
5
|
-
|
|
5
|
+
import { normalizeCIDR } from "./ip.mjs";
|
|
6
6
|
const OwnerTypeDefinition = {
|
|
7
7
|
name: "owner",
|
|
8
8
|
owners: ["location", "owner", "root"],
|
package/src/service.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { Base } from "./base.mjs";
|
|
2
2
|
import { addType } from "./types.mjs";
|
|
3
3
|
import { objectFilter } from "./filter.mjs";
|
|
4
|
-
import { asArray
|
|
4
|
+
import { asArray } from "./utils.mjs";
|
|
5
5
|
import { networkAddressProperties } from "./network-support.mjs";
|
|
6
|
+
import { isLocalhost } from "./ip.mjs";
|
|
6
7
|
import {
|
|
7
8
|
DNSRecord,
|
|
8
9
|
dnsFullName,
|
package/src/services/dhcp.mjs
CHANGED
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
serviceEndpoints
|
|
8
8
|
} from "../service.mjs";
|
|
9
9
|
import { addType } from "../types.mjs";
|
|
10
|
-
import { writeLines
|
|
10
|
+
import { writeLines } from "../utils.mjs";
|
|
11
|
+
import { isIPv4, isIPv6 } from "../ip.mjs";
|
|
11
12
|
|
|
12
13
|
const DHCPServiceTypeDefinition = {
|
|
13
14
|
name: "dhcp",
|
|
@@ -145,7 +146,7 @@ export class DHCPService extends Service {
|
|
|
145
146
|
return {
|
|
146
147
|
name: domain,
|
|
147
148
|
"dns-servers": dnsServerEndpoints
|
|
148
|
-
.filter(endpoint =>
|
|
149
|
+
.filter(endpoint => isIPv4(endpoint.rawAddress))
|
|
149
150
|
.map(endpoint => {
|
|
150
151
|
return { "ip-address": endpoint.rawAddress };
|
|
151
152
|
})
|
|
@@ -229,7 +230,7 @@ export class DHCPService extends Service {
|
|
|
229
230
|
Dhcp4: {
|
|
230
231
|
...commonConfig,
|
|
231
232
|
"interfaces-config": {
|
|
232
|
-
interfaces: listenInterfaces(
|
|
233
|
+
interfaces: listenInterfaces(isIPv4)
|
|
233
234
|
},
|
|
234
235
|
"multi-threading": {
|
|
235
236
|
"enable-multi-threading": false
|
|
@@ -242,7 +243,7 @@ export class DHCPService extends Service {
|
|
|
242
243
|
{
|
|
243
244
|
name: "domain-name-servers",
|
|
244
245
|
data: dnsServerEndpoints
|
|
245
|
-
.filter(endpoint =>
|
|
246
|
+
.filter(endpoint => isIPv4(endpoint.rawAddress))
|
|
246
247
|
.map(endpoint => endpoint.rawAddress)
|
|
247
248
|
.join(",")
|
|
248
249
|
},
|
|
@@ -275,7 +276,7 @@ export class DHCPService extends Service {
|
|
|
275
276
|
Dhcp6: {
|
|
276
277
|
...commonConfig,
|
|
277
278
|
"interfaces-config": {
|
|
278
|
-
interfaces: listenInterfaces(
|
|
279
|
+
interfaces: listenInterfaces(isIPv6)
|
|
279
280
|
},
|
|
280
281
|
"control-socket": {
|
|
281
282
|
"socket-type": "unix",
|
|
@@ -286,7 +287,7 @@ export class DHCPService extends Service {
|
|
|
286
287
|
{
|
|
287
288
|
name: "dns-servers",
|
|
288
289
|
data: dnsServerEndpoints
|
|
289
|
-
.filter(endpoint =>
|
|
290
|
+
.filter(endpoint => isIPv6(endpoint.rawAddress))
|
|
290
291
|
.map(endpoint => endpoint.rawAddress)
|
|
291
292
|
.join(",")
|
|
292
293
|
}
|
package/src/services/dns.mjs
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
import { createHmac } from "node:crypto";
|
|
3
3
|
import { FileContentProvider } from "npm-pkgbuild";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
isLinkLocal,
|
|
8
|
-
isLocalhost
|
|
9
|
-
} from "../utils.mjs";
|
|
10
|
-
import { DNSRecord, dnsFullName, reverseArpaAddress } from "../dns-utils.mjs";
|
|
4
|
+
import { writeLines } from "../utils.mjs";
|
|
5
|
+
import { isIPv6, isLinkLocal, isLocalhost, reverseArpa } from "../ip.mjs";
|
|
6
|
+
import { DNSRecord, dnsFullName } from "../dns-utils.mjs";
|
|
11
7
|
import { addType } from "../types.mjs";
|
|
12
8
|
import { ServiceTypeDefinition, serviceAddresses } from "../service.mjs";
|
|
13
9
|
import {
|
|
@@ -211,9 +207,10 @@ export class DNSService extends ExtraSourceService {
|
|
|
211
207
|
yield packageData;
|
|
212
208
|
}
|
|
213
209
|
|
|
214
|
-
const p2 =
|
|
210
|
+
const p2 = join(dir, "p2");
|
|
215
211
|
|
|
216
212
|
packageData.properties = {
|
|
213
|
+
dir: p2,
|
|
217
214
|
name: `named-zones-${name}`,
|
|
218
215
|
description: `zone definitions for ${location.fullName}`,
|
|
219
216
|
dependencies: ["mf-named"],
|
|
@@ -292,7 +289,7 @@ async function generateZoneDefs(dns, location, packageData) {
|
|
|
292
289
|
for (const address of host.rawAddresses) {
|
|
293
290
|
if (!isLocalhost(address)) {
|
|
294
291
|
zone.records.add(
|
|
295
|
-
DNSRecord("@",
|
|
292
|
+
DNSRecord("@", isIPv6(address) ? "AAAA" : "A", address)
|
|
296
293
|
);
|
|
297
294
|
}
|
|
298
295
|
}
|
|
@@ -366,7 +363,7 @@ async function generateZoneDefs(dns, location, packageData) {
|
|
|
366
363
|
zone.records.add(
|
|
367
364
|
DNSRecord(
|
|
368
365
|
dnsFullName(domainName),
|
|
369
|
-
|
|
366
|
+
isIPv6(address) ? "AAAA" : "A",
|
|
370
367
|
address
|
|
371
368
|
)
|
|
372
369
|
);
|
|
@@ -375,11 +372,11 @@ async function generateZoneDefs(dns, location, packageData) {
|
|
|
375
372
|
let reverseZone = reverseZones.get(subnet.address);
|
|
376
373
|
|
|
377
374
|
if (!reverseZone) {
|
|
378
|
-
const
|
|
375
|
+
const id = reverseArpa(subnet.prefix);
|
|
379
376
|
reverseZone = {
|
|
380
|
-
id
|
|
377
|
+
id,
|
|
381
378
|
type: "plain",
|
|
382
|
-
file: `${locationName}/${
|
|
379
|
+
file: `${locationName}/${id}.zone`,
|
|
383
380
|
records: new Set([SOARecord, NSRecord])
|
|
384
381
|
};
|
|
385
382
|
config.zones.push(reverseZone);
|
|
@@ -389,7 +386,7 @@ async function generateZoneDefs(dns, location, packageData) {
|
|
|
389
386
|
for (const domainName of host.domainNames) {
|
|
390
387
|
reverseZone.records.add(
|
|
391
388
|
DNSRecord(
|
|
392
|
-
dnsFullName(
|
|
389
|
+
dnsFullName(reverseArpa(address)),
|
|
393
390
|
"PTR",
|
|
394
391
|
dnsFullName(domainName)
|
|
395
392
|
)
|
package/src/subnet.mjs
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
normalizeCIDR,
|
|
3
|
-
isLinkLocal,
|
|
4
|
-
isIPv4Address,
|
|
5
|
-
isIPv6Address,
|
|
6
|
-
addressWithPrefixLength
|
|
7
|
-
} from "./utils.mjs";
|
|
1
|
+
import { normalizeCIDR, isLinkLocal, isIPv4, isIPv6, prefixIP } from "./ip.mjs";
|
|
8
2
|
import { Base } from "./base.mjs";
|
|
9
3
|
import { addType } from "./types.mjs";
|
|
10
4
|
|
|
@@ -37,9 +31,13 @@ export class Subnet extends Base {
|
|
|
37
31
|
}
|
|
38
32
|
|
|
39
33
|
constructor(owner, address) {
|
|
40
|
-
const { cidr } = normalizeCIDR(address);
|
|
34
|
+
const { longPrefix, prefix, prefixLength, cidr } = normalizeCIDR(address);
|
|
41
35
|
super(owner, cidr);
|
|
42
36
|
owner.addObject(this);
|
|
37
|
+
|
|
38
|
+
this.prefix = prefix;
|
|
39
|
+
this.prefixLength = prefixLength;
|
|
40
|
+
this.longPrefix = longPrefix;
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
get fullName() {
|
|
@@ -55,36 +53,20 @@ export class Subnet extends Base {
|
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
get isIPv4() {
|
|
58
|
-
return
|
|
56
|
+
return isIPv4(this.address);
|
|
59
57
|
}
|
|
60
58
|
|
|
61
59
|
get isIPv6() {
|
|
62
|
-
return
|
|
60
|
+
return isIPv6(this.address);
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
get addressRange() {
|
|
66
64
|
return [
|
|
67
|
-
|
|
65
|
+
prefixIP(this.prefix, this.prefixLength),
|
|
68
66
|
this.prefix + ".255".repeat((32 - this.prefixLength) / 8)
|
|
69
67
|
];
|
|
70
68
|
}
|
|
71
69
|
|
|
72
|
-
get longPrefix() {
|
|
73
|
-
return addressWithPrefixLength(this.prefix, this.prefixLength);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
get prefix() {
|
|
77
|
-
const [prefix] = this.name.split("/");
|
|
78
|
-
return prefix;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
get prefixLength() {
|
|
82
|
-
const m = this.name.match(/\/(\d+)$/);
|
|
83
|
-
if (m) {
|
|
84
|
-
return parseInt(m[1]);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
70
|
get address() {
|
|
89
71
|
return this.name;
|
|
90
72
|
}
|
package/src/utils.mjs
CHANGED
|
@@ -77,205 +77,3 @@ export function asIterator(value) {
|
|
|
77
77
|
|
|
78
78
|
return asArray(value);
|
|
79
79
|
}
|
|
80
|
-
|
|
81
|
-
export function isIPv4Address(address) {
|
|
82
|
-
switch (typeof address) {
|
|
83
|
-
case "string":
|
|
84
|
-
return address.indexOf(".") >= 0;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export function isIPv6Address(address) {
|
|
91
|
-
switch (typeof address) {
|
|
92
|
-
case "string":
|
|
93
|
-
return address.indexOf(":") >= 0;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function isLinkLocal(address) {
|
|
100
|
-
switch (typeof address) {
|
|
101
|
-
case "string":
|
|
102
|
-
return address.startsWith("fe80");
|
|
103
|
-
|
|
104
|
-
case "bigint":
|
|
105
|
-
return ((address >> 112n) & 0xffffn) === 0xfe80n;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function generateEU64(mac) {
|
|
112
|
-
//TODO
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export function isLocalhost(address) {
|
|
116
|
-
const eaddr = encodeIP(address);
|
|
117
|
-
return eaddr === IPV4_LOCALHOST || eaddr === IPV6_LOCALHOST;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function normalizeIPAddress(address) {
|
|
121
|
-
address = address.replace(/\/\d+$/, "");
|
|
122
|
-
if (isIPv4Address(address)) {
|
|
123
|
-
return address;
|
|
124
|
-
}
|
|
125
|
-
const parts = address.split(":");
|
|
126
|
-
const i = parts.indexOf("");
|
|
127
|
-
if (i >= 0) {
|
|
128
|
-
parts.splice(i, 1, ..."0".repeat(9 - parts.length));
|
|
129
|
-
}
|
|
130
|
-
return parts.map(s => s.padStart(4, "0")).join(":");
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const ipv4 = {
|
|
134
|
-
separator: ".",
|
|
135
|
-
length: 32,
|
|
136
|
-
segmentLength: 8,
|
|
137
|
-
segmentMask: 0xffn,
|
|
138
|
-
mask: 0xffffffffn,
|
|
139
|
-
base: 10
|
|
140
|
-
};
|
|
141
|
-
const ipv6 = {
|
|
142
|
-
separator: ":",
|
|
143
|
-
compressor: "::",
|
|
144
|
-
length: 128,
|
|
145
|
-
segmentLength: 16,
|
|
146
|
-
segmentMask: 0xffffn,
|
|
147
|
-
mask: 0xffffffffffffffffffffffffffffffffn,
|
|
148
|
-
base: 16
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
export function addressWithPrefixLength(address, prefixLength) {
|
|
152
|
-
const definition = ipv4;
|
|
153
|
-
|
|
154
|
-
return (
|
|
155
|
-
address +
|
|
156
|
-
".0".repeat((definition.length - prefixLength) / definition.segmentLength)
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function _decode(definition, address, length = definition.length) {
|
|
161
|
-
if (typeof address === "string") {
|
|
162
|
-
return address;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
let result = "";
|
|
166
|
-
let compressed = 0;
|
|
167
|
-
let shift = definition.length;
|
|
168
|
-
let word;
|
|
169
|
-
const last = length / definition.segmentLength;
|
|
170
|
-
|
|
171
|
-
for (let i = 0, j = 0; i < last; j = j + 1, i = j) {
|
|
172
|
-
for (; j < last; j++) {
|
|
173
|
-
shift -= definition.segmentLength;
|
|
174
|
-
word = (address >> BigInt(shift)) & definition.segmentMask;
|
|
175
|
-
|
|
176
|
-
if (word !== 0n || !definition.compressor || compressed > 0) {
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (j > i + 1) {
|
|
182
|
-
compressed++;
|
|
183
|
-
result += definition.compressor;
|
|
184
|
-
} else {
|
|
185
|
-
if (result.length > 0) {
|
|
186
|
-
result += definition.separator;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if (j < last) {
|
|
191
|
-
result += word.toString(definition.base);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return result;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
export function _encode(definition, address) {
|
|
199
|
-
if (typeof address !== "string") {
|
|
200
|
-
return address;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
let res = 0n;
|
|
204
|
-
let shift = BigInt(definition.length);
|
|
205
|
-
|
|
206
|
-
for (const word of normalizeIPAddress(address)
|
|
207
|
-
.split(definition.separator)
|
|
208
|
-
.map(a => parseInt(a, definition.base))) {
|
|
209
|
-
shift -= BigInt(definition.segmentLength);
|
|
210
|
-
res += BigInt(word) << shift;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return res;
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export function decodeIPv6(address, length) {
|
|
217
|
-
return _decode(ipv6, address, length);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export function encodeIPv6(address) {
|
|
221
|
-
return _encode(ipv6, address);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
export function decodeIPv4(address, length) {
|
|
225
|
-
return _decode(ipv4, address, length);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
export function encodeIPv4(address) {
|
|
229
|
-
return _encode(ipv4, address);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
export function decodeIP(address, length) {
|
|
233
|
-
return _decode(isIPv4Address(address) ? ipv4 : ipv6, address, length);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
export function encodeIP(address) {
|
|
237
|
-
return _encode(isIPv4Address(address) ? ipv4 : ipv6, address);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
export function formatCIDR(address, subnet) {
|
|
241
|
-
return subnet ? `${address}/${subnet.prefixLength}` : address;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
export function normalizeCIDR(address) {
|
|
245
|
-
let [prefix, prefixLength] = address.split(/\//);
|
|
246
|
-
|
|
247
|
-
if (!prefixLength && isLinkLocal(address)) {
|
|
248
|
-
prefix = "fe80::";
|
|
249
|
-
prefixLength = 64;
|
|
250
|
-
} else {
|
|
251
|
-
const definition = isIPv6Address(prefix) ? ipv6 : ipv4;
|
|
252
|
-
let n = _encode(definition, prefix);
|
|
253
|
-
|
|
254
|
-
if (prefixLength) {
|
|
255
|
-
n = n & (definition.mask << BigInt(definition.length - prefixLength));
|
|
256
|
-
prefix = _decode(definition, n, prefixLength);
|
|
257
|
-
} else {
|
|
258
|
-
if (n === IPV4_LOCALHOST) {
|
|
259
|
-
prefixLength = 8;
|
|
260
|
-
prefix = _decode(definition, n, prefixLength);
|
|
261
|
-
} else if (n === IPV6_LOCALHOST) {
|
|
262
|
-
prefixLength = 128;
|
|
263
|
-
prefix = _decode(definition, n, prefixLength);
|
|
264
|
-
} else {
|
|
265
|
-
return {};
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return { prefix, prefixLength, cidr: `${prefix}/${prefixLength}` };
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
export function hasWellKnownSubnet(address) {
|
|
274
|
-
const n = encodeIP(address);
|
|
275
|
-
return n === IPV4_LOCALHOST || n === IPV6_LOCALHOST || isLinkLocal(address);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
export const IPV4_LOCALHOST = _encode(ipv4, "127.0.0.1");
|
|
279
|
-
export const IPV6_LOCALHOST = _encode(ipv6, "::1");
|
|
280
|
-
export const IPV6_LINK_LOCAL_BROADCAST = _encode(ipv6, "ff02::1");
|
|
281
|
-
export const IPV6_ROUTER_BROADCAST = _encode(ipv6, "ff02::2");
|
package/types/dns-utils.d.mts
CHANGED
package/types/ip.d.mts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function IPV4(...args: any[]): any;
|
|
2
|
+
export function IPV6(...args: any[]): any;
|
|
3
|
+
export function encodeIP(address: any): any;
|
|
4
|
+
export function encodeIPv6(address: any): any;
|
|
5
|
+
export function encodeIPv4(address: any): any;
|
|
6
|
+
export function _encode(definition: any, address: any): any;
|
|
7
|
+
export function decodeIPv6(address: any, length: any): string;
|
|
8
|
+
export function decodeIPv4(address: any, length: any): string;
|
|
9
|
+
export function decodeIP(address: any, length: any): string;
|
|
10
|
+
export function isIPv4(address: any): boolean;
|
|
11
|
+
export function isIPv6(address: any): boolean;
|
|
12
|
+
export function _is(definition: any, address: any): boolean;
|
|
13
|
+
export function asBigInt(address: any): bigint;
|
|
14
|
+
export function prefixIP(address: any, length: any): string;
|
|
15
|
+
export function _prefix(definition: any, address: any, length: any): bigint;
|
|
16
|
+
export function normalizeCIDR(address: any): {
|
|
17
|
+
longPrefix?: undefined;
|
|
18
|
+
prefix?: undefined;
|
|
19
|
+
prefixLength?: undefined;
|
|
20
|
+
cidr?: undefined;
|
|
21
|
+
} | {
|
|
22
|
+
longPrefix: any;
|
|
23
|
+
prefix: any;
|
|
24
|
+
prefixLength: any;
|
|
25
|
+
cidr: string;
|
|
26
|
+
};
|
|
27
|
+
export function formatCIDR(address: any, subnet: any): any;
|
|
28
|
+
export function normalizeIP(address: any): string;
|
|
29
|
+
export function reverseArpa(address: any): string;
|
|
30
|
+
export function isLocalhost(address: any): boolean;
|
|
31
|
+
export function isLinkLocal(address: any): boolean;
|
|
32
|
+
export function hasWellKnownSubnet(address: any): boolean;
|
|
33
|
+
export const IPV6_LINK_LOCAL_BROADCAST: any;
|
|
34
|
+
export const IPV6_ROUTER_BROADCAST: any;
|
|
35
|
+
export const IPV4_LOCALHOST: any;
|
|
36
|
+
export const IPV6_LOCALHOST: any;
|
package/types/subnet.d.mts
CHANGED
|
@@ -25,15 +25,15 @@ export class Subnet extends Base {
|
|
|
25
25
|
};
|
|
26
26
|
};
|
|
27
27
|
networks: Set<any>;
|
|
28
|
+
prefix: any;
|
|
29
|
+
prefixLength: any;
|
|
30
|
+
longPrefix: any;
|
|
28
31
|
get fullName(): string;
|
|
29
32
|
matchesAddress(address: any): any;
|
|
30
33
|
get isLinkLocal(): boolean;
|
|
31
34
|
get isIPv4(): boolean;
|
|
32
35
|
get isIPv6(): boolean;
|
|
33
36
|
get addressRange(): string[];
|
|
34
|
-
get longPrefix(): string;
|
|
35
|
-
get prefix(): string;
|
|
36
|
-
get prefixLength(): number;
|
|
37
37
|
get address(): string;
|
|
38
38
|
get longAddress(): string;
|
|
39
39
|
_traverse(...args: any[]): boolean;
|
package/types/utils.d.mts
CHANGED
|
@@ -5,32 +5,3 @@ export function sectionLines(sectionName: any, values: any): string[];
|
|
|
5
5
|
export function bridgeToJSON(bridge: any): any[];
|
|
6
6
|
export function asArray(value: any): any[];
|
|
7
7
|
export function asIterator(value: any): any;
|
|
8
|
-
export function isIPv4Address(address: any): boolean;
|
|
9
|
-
export function isIPv6Address(address: any): boolean;
|
|
10
|
-
export function isLinkLocal(address: any): boolean;
|
|
11
|
-
export function generateEU64(mac: any): void;
|
|
12
|
-
export function isLocalhost(address: any): boolean;
|
|
13
|
-
export function normalizeIPAddress(address: any): any;
|
|
14
|
-
export function addressWithPrefixLength(address: any, prefixLength: any): string;
|
|
15
|
-
export function _encode(definition: any, address: any): any;
|
|
16
|
-
export function decodeIPv6(address: any, length: any): string;
|
|
17
|
-
export function encodeIPv6(address: any): any;
|
|
18
|
-
export function decodeIPv4(address: any, length: any): string;
|
|
19
|
-
export function encodeIPv4(address: any): any;
|
|
20
|
-
export function decodeIP(address: any, length: any): string;
|
|
21
|
-
export function encodeIP(address: any): any;
|
|
22
|
-
export function formatCIDR(address: any, subnet: any): any;
|
|
23
|
-
export function normalizeCIDR(address: any): {
|
|
24
|
-
prefix?: undefined;
|
|
25
|
-
prefixLength?: undefined;
|
|
26
|
-
cidr?: undefined;
|
|
27
|
-
} | {
|
|
28
|
-
prefix: any;
|
|
29
|
-
prefixLength: any;
|
|
30
|
-
cidr: string;
|
|
31
|
-
};
|
|
32
|
-
export function hasWellKnownSubnet(address: any): boolean;
|
|
33
|
-
export const IPV4_LOCALHOST: any;
|
|
34
|
-
export const IPV6_LOCALHOST: any;
|
|
35
|
-
export const IPV6_LINK_LOCAL_BROADCAST: any;
|
|
36
|
-
export const IPV6_ROUTER_BROADCAST: any;
|