pmcf 1.34.0 → 1.35.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/bin/pmcf-named-defs +5 -5
- package/package.json +2 -2
- package/src/model.mjs +38 -29
- package/src/owner.mjs +65 -49
- package/src/utils.mjs +28 -0
- package/types/model.d.mts +8 -3
- package/types/owner.d.mts +7 -6
- package/types/utils.d.mts +10 -0
package/bin/pmcf-named-defs
CHANGED
|
@@ -78,15 +78,15 @@ async function generateNamedDefs(owner, targetDir) {
|
|
|
78
78
|
zones.push(zone);
|
|
79
79
|
|
|
80
80
|
for (const subnet of owner.subnets()) {
|
|
81
|
-
if (subnet.
|
|
82
|
-
const reverseArpa = reverseArpaAddress(subnet.
|
|
83
|
-
const
|
|
81
|
+
if (subnet.prefix) {
|
|
82
|
+
const reverseArpa = reverseArpaAddress(subnet.prefix);
|
|
83
|
+
const reverseZone = {
|
|
84
84
|
id: reverseArpa,
|
|
85
85
|
file: `${reverseArpa}.zone`,
|
|
86
86
|
records: new Set([SOARecord, NSRecord])
|
|
87
87
|
};
|
|
88
|
-
zones.push(
|
|
89
|
-
subnet.reverseZone =
|
|
88
|
+
zones.push(reverseZone);
|
|
89
|
+
subnet.reverseZone = reverseZone;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pmcf",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.35.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"pacc": "^3.3.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"@types/node": "^22.13.
|
|
46
|
+
"@types/node": "^22.13.1",
|
|
47
47
|
"ava": "^6.2.0",
|
|
48
48
|
"c8": "^10.1.3",
|
|
49
49
|
"documentation": "^14.0.3",
|
package/src/model.mjs
CHANGED
|
@@ -342,15 +342,21 @@ export class Host extends Base {
|
|
|
342
342
|
*networkAddresses() {
|
|
343
343
|
for (const networkInterface of Object.values(this.networkInterfaces)) {
|
|
344
344
|
for (const address of networkInterface.ipAddresses) {
|
|
345
|
-
yield {
|
|
345
|
+
yield {
|
|
346
|
+
networkInterface,
|
|
347
|
+
address,
|
|
348
|
+
addressWithPrefixLength:
|
|
349
|
+
networkInterface.addressWithPrefixLength(address)
|
|
350
|
+
};
|
|
346
351
|
}
|
|
347
352
|
}
|
|
348
353
|
}
|
|
349
354
|
|
|
350
355
|
get ipAddresses() {
|
|
351
|
-
return [...this.networkAddresses()].map(na =>
|
|
352
|
-
|
|
353
|
-
|
|
356
|
+
return [...this.networkAddresses()].map(na => na.address);
|
|
357
|
+
}
|
|
358
|
+
get ipAddressesWithPrefixLength() {
|
|
359
|
+
return [...this.networkAddresses()].map(na => na.addressWithPrefixLength);
|
|
354
360
|
}
|
|
355
361
|
|
|
356
362
|
get ipAddress() {
|
|
@@ -391,7 +397,7 @@ export class NetworkInterface extends Base {
|
|
|
391
397
|
return "network_interface";
|
|
392
398
|
}
|
|
393
399
|
|
|
394
|
-
#ipAddresses =
|
|
400
|
+
#ipAddresses = new Map();
|
|
395
401
|
#scope;
|
|
396
402
|
#metric;
|
|
397
403
|
#ssid;
|
|
@@ -404,21 +410,6 @@ export class NetworkInterface extends Base {
|
|
|
404
410
|
constructor(owner, data) {
|
|
405
411
|
super(owner, data);
|
|
406
412
|
|
|
407
|
-
if (data.ipv4) {
|
|
408
|
-
this.#ipAddresses.push(...asArray(data.ipv4));
|
|
409
|
-
delete data.ipv4;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
if (data.ipv6) {
|
|
413
|
-
this.#ipAddresses.push(...asArray(data.ipv6));
|
|
414
|
-
delete data.ipv6;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
if (data.ipAddresses) {
|
|
418
|
-
this.#ipAddresses.push(...asArray(data.ipAddresses));
|
|
419
|
-
delete data.ipAddresses;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
413
|
if (data.ssid) {
|
|
423
414
|
this.#ssid = data.ssid;
|
|
424
415
|
delete data.ssid;
|
|
@@ -462,26 +453,44 @@ export class NetworkInterface extends Base {
|
|
|
462
453
|
//this.arpbridge = owner.addARPBridge(this, data.arpbridge);
|
|
463
454
|
}
|
|
464
455
|
|
|
456
|
+
set ipAddresses(value) {
|
|
457
|
+
const networkOwner = this.owner.owner;
|
|
458
|
+
for (const address of asArray(value)) {
|
|
459
|
+
const subnet = networkOwner.createSubnet(address);
|
|
460
|
+
this.#ipAddresses.set(normalizeIPAddress(address), subnet);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
subnetForAddress(address) {
|
|
465
|
+
return (
|
|
466
|
+
this.network?.subnetForAddress(address) ||
|
|
467
|
+
this.owner.owner.subnetForAddress(address)
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
addressWithPrefixLength(address) {
|
|
472
|
+
return `${address}/${this.subnetForAddress(address)?.prefixLength}`;
|
|
473
|
+
}
|
|
474
|
+
|
|
465
475
|
get ipAddresses() {
|
|
466
|
-
return this.#ipAddresses;
|
|
476
|
+
return this.#ipAddresses.keys();
|
|
467
477
|
}
|
|
468
478
|
|
|
469
479
|
get ipAddressesWithPrefixLength() {
|
|
470
|
-
return this
|
|
471
|
-
|
|
480
|
+
return [...this.ipAddresses].map(address =>
|
|
481
|
+
this.addressWithPrefixLength(address)
|
|
472
482
|
);
|
|
473
483
|
}
|
|
474
484
|
|
|
475
485
|
get ipv4Addresses() {
|
|
476
|
-
return this
|
|
486
|
+
return [...this.ipAddresses].filter(a => isIPv4Address(a));
|
|
477
487
|
}
|
|
478
488
|
|
|
479
489
|
get ipv6Addresses() {
|
|
480
|
-
return this
|
|
490
|
+
return [...this.ipAddresses].filter(a => isIPv6Address(a));
|
|
481
491
|
}
|
|
482
492
|
|
|
483
|
-
get prefixLength()
|
|
484
|
-
{
|
|
493
|
+
get prefixLength() {
|
|
485
494
|
return this.network?.prefixLength;
|
|
486
495
|
}
|
|
487
496
|
|
|
@@ -538,8 +547,8 @@ export class NetworkInterface extends Base {
|
|
|
538
547
|
"psk",
|
|
539
548
|
"scope",
|
|
540
549
|
"metric",
|
|
541
|
-
"
|
|
542
|
-
"
|
|
550
|
+
"kind",
|
|
551
|
+
"ipAddresses"
|
|
543
552
|
];
|
|
544
553
|
}
|
|
545
554
|
}
|
package/src/owner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { asArray } from "./utils.mjs";
|
|
1
|
+
import { asArray, normalizeCIDR } from "./utils.mjs";
|
|
2
2
|
import { Base } from "./base.mjs";
|
|
3
3
|
import { DNSService } from "./dns.mjs";
|
|
4
4
|
|
|
@@ -160,6 +160,32 @@ export class Owner extends Base {
|
|
|
160
160
|
return this.typeList("subnet");
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
subnetForAddress(address) {
|
|
164
|
+
for (const subnet of this.subnets()) {
|
|
165
|
+
if (subnet.matchesAddress(address)) {
|
|
166
|
+
return subnet;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
createSubnet(address) {
|
|
172
|
+
if (address instanceof Subnet) {
|
|
173
|
+
return address;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const { cidr } = normalizeCIDR(address);
|
|
177
|
+
|
|
178
|
+
if (cidr) {
|
|
179
|
+
let subnet = this.subnetNamed(cidr);
|
|
180
|
+
|
|
181
|
+
if (!subnet) {
|
|
182
|
+
subnet = new Subnet(this, { name: cidr });
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return subnet;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
163
189
|
clusterNamed(name) {
|
|
164
190
|
return this.typeNamed("cluster", name);
|
|
165
191
|
}
|
|
@@ -260,9 +286,8 @@ export class Network extends Owner {
|
|
|
260
286
|
kind;
|
|
261
287
|
scope;
|
|
262
288
|
metric;
|
|
263
|
-
subnet;
|
|
264
289
|
bridge;
|
|
265
|
-
|
|
290
|
+
gateway;
|
|
266
291
|
|
|
267
292
|
static get typeName() {
|
|
268
293
|
return "network";
|
|
@@ -271,9 +296,9 @@ export class Network extends Owner {
|
|
|
271
296
|
constructor(owner, data) {
|
|
272
297
|
super(owner, data);
|
|
273
298
|
|
|
274
|
-
if (data.
|
|
275
|
-
this
|
|
276
|
-
delete data.
|
|
299
|
+
if (data.subnets) {
|
|
300
|
+
this.addSubnets(data.subnets);
|
|
301
|
+
delete data.subnets;
|
|
277
302
|
}
|
|
278
303
|
|
|
279
304
|
let bridge;
|
|
@@ -284,18 +309,6 @@ export class Network extends Owner {
|
|
|
284
309
|
|
|
285
310
|
Object.assign(this, data);
|
|
286
311
|
|
|
287
|
-
const subnetAddress = this.subnetAddress;
|
|
288
|
-
|
|
289
|
-
if (subnetAddress) {
|
|
290
|
-
let subnet = owner.subnetNamed(subnetAddress);
|
|
291
|
-
if (!subnet) {
|
|
292
|
-
subnet = new Subnet(owner, { name: subnetAddress });
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
this.subnet = subnet;
|
|
296
|
-
subnet.networks.add(this);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
312
|
this.bridge = owner.addBridge(this, bridge);
|
|
300
313
|
}
|
|
301
314
|
|
|
@@ -306,32 +319,11 @@ export class Network extends Owner {
|
|
|
306
319
|
return super.networkNamed(name);
|
|
307
320
|
}
|
|
308
321
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return this.#ipAddresses;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
get prefixLength() {
|
|
318
|
-
for (const a of this.#ipAddresses) {
|
|
319
|
-
const m = a.match(/\/(\d+)$/);
|
|
320
|
-
if (m) {
|
|
321
|
-
return parseInt(m[1]);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
this.error("no prefixLength", this.#ipAddresses);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
get subnetAddress() {
|
|
329
|
-
for (const a of this.#ipAddresses) {
|
|
330
|
-
const [addr, bits] = a.split(/\//);
|
|
331
|
-
if (bits) {
|
|
332
|
-
const parts = addr.split(/\./);
|
|
333
|
-
return parts.slice(0, bits / 8).join(".");
|
|
334
|
-
}
|
|
322
|
+
addSubnets(value) {
|
|
323
|
+
for (const address of asArray(value)) {
|
|
324
|
+
const subnet = this.owner.createSubnet(address);
|
|
325
|
+
this.addObject(subnet);
|
|
326
|
+
subnet.networks.add(this);
|
|
335
327
|
}
|
|
336
328
|
}
|
|
337
329
|
|
|
@@ -339,12 +331,10 @@ export class Network extends Owner {
|
|
|
339
331
|
return [
|
|
340
332
|
...super.propertyNames,
|
|
341
333
|
"kind",
|
|
342
|
-
"ipAddresses",
|
|
343
|
-
"subnet",
|
|
344
|
-
"prefixLength",
|
|
345
334
|
"scope",
|
|
346
335
|
"metric",
|
|
347
|
-
"bridge"
|
|
336
|
+
"bridge",
|
|
337
|
+
"gateway"
|
|
348
338
|
];
|
|
349
339
|
}
|
|
350
340
|
}
|
|
@@ -357,6 +347,16 @@ export class Subnet extends Base {
|
|
|
357
347
|
}
|
|
358
348
|
|
|
359
349
|
constructor(owner, data) {
|
|
350
|
+
const { cidr } = normalizeCIDR(data.name);
|
|
351
|
+
|
|
352
|
+
if(!cidr) {
|
|
353
|
+
const error = Error(`Invalid address`);
|
|
354
|
+
error.address = data.name;
|
|
355
|
+
throw error;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
data.name = cidr;
|
|
359
|
+
|
|
360
360
|
super(owner, data);
|
|
361
361
|
|
|
362
362
|
Object.assign(this, data);
|
|
@@ -364,12 +364,28 @@ export class Subnet extends Base {
|
|
|
364
364
|
owner.addObject(this);
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
+
matchesAddress(address) {
|
|
368
|
+
return address.startsWith(this.prefix);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
get prefix() {
|
|
372
|
+
const [prefix] = this.name.split("/");
|
|
373
|
+
return prefix;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
get prefixLength() {
|
|
377
|
+
const m = this.name.match(/\/(\d+)$/);
|
|
378
|
+
if (m) {
|
|
379
|
+
return parseInt(m[1]);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
367
383
|
get address() {
|
|
368
384
|
return this.name;
|
|
369
385
|
}
|
|
370
386
|
|
|
371
387
|
get propertyNames() {
|
|
372
|
-
return [...super.propertyNames, "networks"];
|
|
388
|
+
return [...super.propertyNames, "networks", "prefixLength"];
|
|
373
389
|
}
|
|
374
390
|
|
|
375
391
|
_traverse(...args) {
|
package/src/utils.mjs
CHANGED
|
@@ -40,6 +40,10 @@ export function isIPv6Address(address) {
|
|
|
40
40
|
return address.indexOf(":") >= 0;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
export function isLinkLocal(address) {
|
|
44
|
+
return address.startsWith("fe80");
|
|
45
|
+
}
|
|
46
|
+
|
|
43
47
|
export function normalizeIPAddress(address) {
|
|
44
48
|
address = address.replace(/\/\d+$/, "");
|
|
45
49
|
if (isIPv4Address(address)) {
|
|
@@ -52,3 +56,27 @@ export function normalizeIPAddress(address) {
|
|
|
52
56
|
}
|
|
53
57
|
return parts.map(s => s.padStart(4, "0")).join(":");
|
|
54
58
|
}
|
|
59
|
+
|
|
60
|
+
export function normalizeCIDR(address) {
|
|
61
|
+
let [prefix, prefixLength] = address.split(/\//);
|
|
62
|
+
|
|
63
|
+
if (!prefixLength && isLinkLocal(address)) {
|
|
64
|
+
prefix = "fe80::";
|
|
65
|
+
prefixLength = 64;
|
|
66
|
+
} else {
|
|
67
|
+
if (prefixLength) {
|
|
68
|
+
if (isIPv4Address(prefix)) {
|
|
69
|
+
const parts = prefix.split(/\./);
|
|
70
|
+
prefix = parts.slice(0, prefixLength / 8).join(".");
|
|
71
|
+
} else {
|
|
72
|
+
prefix = normalizeIPAddress(prefix);
|
|
73
|
+
const parts = prefix.split(/\:/);
|
|
74
|
+
prefix = parts.slice(0, prefixLength / 16).join(":");
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
return {};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { prefix, prefixLength, cidr: `${prefix}/${prefixLength}` };
|
|
82
|
+
}
|
package/types/model.d.mts
CHANGED
|
@@ -38,10 +38,12 @@ export class Host extends Base {
|
|
|
38
38
|
services(filter: any): Generator<any, void, unknown>;
|
|
39
39
|
addNetworkInterface(networkInterface: any): void;
|
|
40
40
|
networkAddresses(): Generator<{
|
|
41
|
-
address: any;
|
|
42
41
|
networkInterface: any;
|
|
42
|
+
address: any;
|
|
43
|
+
addressWithPrefixLength: any;
|
|
43
44
|
}, void, unknown>;
|
|
44
45
|
get ipAddresses(): any[];
|
|
46
|
+
get ipAddressesWithPrefixLength(): any[];
|
|
45
47
|
get ipAddress(): any;
|
|
46
48
|
publicKey(type?: string): Promise<string>;
|
|
47
49
|
toJSON(): {
|
|
@@ -55,8 +57,11 @@ export class NetworkInterface extends Base {
|
|
|
55
57
|
hwaddr: any;
|
|
56
58
|
set network(networkOrName: any);
|
|
57
59
|
get network(): any;
|
|
58
|
-
|
|
59
|
-
get
|
|
60
|
+
set ipAddresses(value: MapIterator<any>);
|
|
61
|
+
get ipAddresses(): MapIterator<any>;
|
|
62
|
+
subnetForAddress(address: any): any;
|
|
63
|
+
addressWithPrefixLength(address: any): string;
|
|
64
|
+
get ipAddressesWithPrefixLength(): string[];
|
|
60
65
|
get ipv4Addresses(): any[];
|
|
61
66
|
get ipv6Addresses(): any[];
|
|
62
67
|
get prefixLength(): any;
|
package/types/owner.d.mts
CHANGED
|
@@ -21,6 +21,8 @@ export class Owner extends Base {
|
|
|
21
21
|
networks(): Generator<any, void, unknown>;
|
|
22
22
|
subnetNamed(name: any): any;
|
|
23
23
|
subnets(): Generator<any, void, unknown>;
|
|
24
|
+
subnetForAddress(address: any): any;
|
|
25
|
+
createSubnet(address: any): any;
|
|
24
26
|
clusterNamed(name: any): any;
|
|
25
27
|
clusters(): Generator<any, void, unknown>;
|
|
26
28
|
addBridge(network: any, destinationNetworks: any): any;
|
|
@@ -34,16 +36,15 @@ export class Network extends Owner {
|
|
|
34
36
|
kind: any;
|
|
35
37
|
scope: any;
|
|
36
38
|
metric: any;
|
|
37
|
-
subnet: any;
|
|
38
39
|
bridge: any;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
get prefixLength(): number;
|
|
42
|
-
get subnetAddress(): any;
|
|
43
|
-
#private;
|
|
40
|
+
gateway: any;
|
|
41
|
+
addSubnets(value: any): void;
|
|
44
42
|
}
|
|
45
43
|
export class Subnet extends Base {
|
|
46
44
|
networks: Set<any>;
|
|
45
|
+
matchesAddress(address: any): any;
|
|
46
|
+
get prefix(): any;
|
|
47
|
+
get prefixLength(): number;
|
|
47
48
|
get address(): any;
|
|
48
49
|
_traverse(...args: any[]): boolean;
|
|
49
50
|
}
|
package/types/utils.d.mts
CHANGED
|
@@ -4,4 +4,14 @@ export function bridgeToJSON(bridge: any): any[];
|
|
|
4
4
|
export function asArray(value: any): any[];
|
|
5
5
|
export function isIPv4Address(address: any): boolean;
|
|
6
6
|
export function isIPv6Address(address: any): boolean;
|
|
7
|
+
export function isLinkLocal(address: any): any;
|
|
7
8
|
export function normalizeIPAddress(address: any): any;
|
|
9
|
+
export function normalizeCIDR(address: any): {
|
|
10
|
+
prefix?: undefined;
|
|
11
|
+
prefixLength?: undefined;
|
|
12
|
+
cidr?: undefined;
|
|
13
|
+
} | {
|
|
14
|
+
prefix: any;
|
|
15
|
+
prefixLength: any;
|
|
16
|
+
cidr: string;
|
|
17
|
+
};
|