@takodotid/circuit 0.34.3 → 0.36.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/README.md +14 -15
- package/dist/chunks/index-20kcjxjg.js +174 -0
- package/dist/chunks/index-2r4bbhac.js +977 -0
- package/dist/chunks/index-n7w3tg5y.js +149 -0
- package/dist/chunks/new-w3zys5y4.js +172 -0
- package/dist/chunks/server-gzsf5me5.js +259 -0
- package/dist/cli/index.js +11345 -9024
- package/dist/helpers/index.js +594 -0
- package/dist/index.js +9 -28
- package/dist/types/core/{addresses.d.ts → address-space.d.ts} +23 -7
- package/dist/types/core/address.d.ts +44 -0
- package/dist/types/core/cabling.d.ts +41 -0
- package/dist/types/core/cross-checks.d.ts +28 -0
- package/dist/types/core/define.d.ts +25 -3
- package/dist/types/core/project-files.d.ts +12 -0
- package/dist/types/core/schema-docs.d.ts +13 -4
- package/dist/types/core/secrets.d.ts +62 -21
- package/dist/types/core/{graph.d.ts → topology.d.ts} +32 -12
- package/dist/types/core/utils.d.ts +8 -0
- package/dist/types/core/validator.d.ts +19 -0
- package/dist/types/helpers/bgp.d.ts +97 -0
- package/dist/types/helpers/checks.d.ts +32 -0
- package/dist/types/helpers/exchange.d.ts +49 -0
- package/dist/types/helpers/filters.d.ts +51 -0
- package/dist/types/helpers/index.d.ts +10 -0
- package/dist/types/helpers/route-server.d.ts +52 -0
- package/dist/types/index.d.ts +5 -3
- package/dist/types/integrations/librenms.d.ts +60 -0
- package/dist/types/integrations/netbox.d.ts +89 -0
- package/dist/types/integrations/peeringdb.d.ts +24 -0
- package/dist/types/integrations/prometheus.d.ts +24 -0
- package/dist/types/integrations/registries.d.ts +8 -0
- package/dist/types/platforms/bgp-wait.d.ts +18 -0
- package/dist/types/platforms/catalog.d.ts +109 -0
- package/dist/types/platforms/derive.d.ts +17 -0
- package/dist/types/platforms/fortios/firewall.d.ts +45 -0
- package/dist/types/platforms/fortios/index.d.ts +134 -0
- package/dist/types/platforms/fortios/names.d.ts +52 -0
- package/dist/types/platforms/fortios/plan.d.ts +104 -0
- package/dist/types/platforms/fortios/render.d.ts +75 -0
- package/dist/types/platforms/fortios/routing.d.ts +56 -0
- package/dist/types/platforms/fortios/tree.d.ts +37 -0
- package/dist/types/platforms/index.d.ts +13 -0
- package/dist/types/platforms/junos/bgp.d.ts +44 -0
- package/dist/types/platforms/junos/index.d.ts +114 -0
- package/dist/types/platforms/junos/render.d.ts +154 -0
- package/dist/types/platforms/line-diff.d.ts +67 -0
- package/dist/types/platforms/platform.d.ts +120 -0
- package/dist/types/platforms/raisecom-ros/index.d.ts +71 -0
- package/dist/types/platforms/raisecom-ros/render.d.ts +41 -0
- package/dist/types/platforms/routeros/export.d.ts +59 -0
- package/dist/types/platforms/routeros/index.d.ts +96 -0
- package/dist/types/{adapters/devices → platforms}/routeros/models.d.ts +4 -0
- package/dist/types/platforms/routeros/plan.d.ts +54 -0
- package/dist/types/platforms/routeros/render.d.ts +240 -0
- package/dist/types/platforms/vrp/index.d.ts +83 -0
- package/dist/types/platforms/vrp/render.d.ts +96 -0
- package/dist/types/schema/common.d.ts +12 -6
- package/dist/types/schema/index.d.ts +1 -0
- package/dist/types/schema/interfaces.d.ts +14 -6
- package/dist/types/schema/policy.d.ts +18 -10
- package/dist/types/schema/routing.d.ts +14 -1
- package/dist/types/schema/system.d.ts +16 -6
- package/dist/types/schema/time-zones.d.ts +2 -0
- package/dist/types/transport/console.d.ts +79 -23
- package/dist/types/transport/path-check.d.ts +32 -0
- package/dist/types/transport/ssh.d.ts +17 -15
- package/package.json +18 -12
- package/src/cli/graph-format.ts +91 -0
- package/src/cli/index.ts +1074 -484
- package/src/cli/new.ts +208 -175
- package/src/cli/rename.ts +97 -91
- package/src/core/address-space.ts +320 -0
- package/src/core/address.ts +202 -0
- package/src/core/cabling.ts +154 -0
- package/src/core/cross-checks.ts +364 -0
- package/src/core/define.ts +26 -3
- package/src/core/project-files.ts +35 -0
- package/src/core/schema-docs.ts +138 -130
- package/src/core/secrets.ts +170 -76
- package/src/core/topology.ts +656 -0
- package/src/core/utils.ts +37 -0
- package/src/core/validator.ts +407 -0
- package/src/helpers/bgp.ts +301 -0
- package/src/helpers/checks.ts +178 -0
- package/src/helpers/exchange.ts +117 -0
- package/src/helpers/filters.ts +107 -0
- package/src/helpers/index.ts +12 -0
- package/src/helpers/route-server.ts +212 -0
- package/src/index.ts +6 -3
- package/src/integrations/librenms.ts +291 -0
- package/src/integrations/netbox.ts +620 -0
- package/src/integrations/peeringdb.ts +173 -0
- package/src/integrations/prometheus.ts +90 -0
- package/src/integrations/registries.ts +25 -0
- package/src/platforms/bgp-wait.ts +41 -0
- package/src/platforms/catalog.ts +69 -0
- package/src/platforms/derive.ts +117 -0
- package/src/{adapters/devices → platforms}/fortios/TRAPS.md +6 -0
- package/src/platforms/fortios/firewall.ts +377 -0
- package/src/platforms/fortios/index.ts +1060 -0
- package/src/platforms/fortios/names.ts +130 -0
- package/src/platforms/fortios/plan.ts +929 -0
- package/src/platforms/fortios/render.ts +779 -0
- package/src/platforms/fortios/routing.ts +476 -0
- package/src/platforms/fortios/tree.ts +129 -0
- package/src/platforms/index.ts +36 -0
- package/src/{adapters/devices → platforms}/junos/TRAPS.md +8 -0
- package/src/platforms/junos/bgp.ts +293 -0
- package/src/platforms/junos/index.ts +1006 -0
- package/src/platforms/junos/render.ts +967 -0
- package/src/platforms/line-diff.ts +244 -0
- package/src/platforms/platform.ts +122 -0
- package/src/platforms/raisecom-ros/TRAPS.md +40 -0
- package/src/platforms/raisecom-ros/index.ts +731 -0
- package/src/platforms/raisecom-ros/render.ts +328 -0
- package/src/{adapters/devices → platforms}/routeros/TRAPS.md +16 -2
- package/src/platforms/routeros/export.ts +342 -0
- package/src/platforms/routeros/index.ts +636 -0
- package/src/{adapters/devices → platforms}/routeros/models.ts +2 -0
- package/src/platforms/routeros/plan.ts +444 -0
- package/src/platforms/routeros/render.ts +1483 -0
- package/src/platforms/vrp/TRAPS.md +45 -0
- package/src/platforms/vrp/index.ts +652 -0
- package/src/platforms/vrp/render.ts +615 -0
- package/src/schema/common.ts +15 -6
- package/src/schema/index.ts +1 -0
- package/src/schema/interfaces.ts +15 -5
- package/src/schema/policy.ts +22 -10
- package/src/schema/routing.ts +16 -1
- package/src/schema/system.ts +16 -6
- package/src/schema/time-zones.ts +482 -0
- package/src/studio/data.ts +172 -168
- package/src/studio/git.ts +95 -90
- package/src/studio/public/app.js +161 -150
- package/src/studio/public/compare.js +219 -212
- package/src/studio/public/diff.js +77 -75
- package/src/studio/public/dom.js +118 -108
- package/src/studio/public/evaluate.js +584 -545
- package/src/studio/public/export.js +120 -118
- package/src/studio/public/graph.js +1343 -1266
- package/src/studio/public/net.js +115 -109
- package/src/studio/public/tables.js +1135 -1083
- package/src/studio/public/tools.js +561 -529
- package/src/studio/server.ts +202 -196
- package/src/transport/console.ts +363 -271
- package/src/transport/path-check.ts +91 -0
- package/src/transport/ssh.ts +98 -94
- package/templates/colocation/checks.ts +11 -6
- package/templates/colocation/edge-01.ts +9 -9
- package/templates/colocation/routing.ts +2 -2
- package/templates/colocation/tenancy.ts +3 -3
- package/templates/colocation/tor-01.ts +3 -3
- package/templates/edge-router/checks.ts +4 -4
- package/templates/edge-router/edge-01.ts +5 -5
- package/templates/edge-router/routing.ts +2 -2
- package/templates/project/AGENTS.md +5 -1
- package/templates/single-site/checks.ts +2 -2
- package/dist/chunks/index-47debt16.js +0 -956
- package/dist/chunks/index-v8zgr7wm.js +0 -128
- package/dist/chunks/new-ny89s7y7.js +0 -166
- package/dist/chunks/server-tjbb3rqc.js +0 -251
- package/dist/presets/index.js +0 -394
- package/dist/types/adapters/devices/catalog.d.ts +0 -86
- package/dist/types/adapters/devices/derive.d.ts +0 -7
- package/dist/types/adapters/devices/fortios/firewall.d.ts +0 -23
- package/dist/types/adapters/devices/fortios/index.d.ts +0 -58
- package/dist/types/adapters/devices/fortios/names.d.ts +0 -48
- package/dist/types/adapters/devices/fortios/plan.d.ts +0 -28
- package/dist/types/adapters/devices/fortios/render.d.ts +0 -38
- package/dist/types/adapters/devices/fortios/routing.d.ts +0 -32
- package/dist/types/adapters/devices/fortios/tree.d.ts +0 -33
- package/dist/types/adapters/devices/index.d.ts +0 -3
- package/dist/types/adapters/devices/junos/bgp.d.ts +0 -11
- package/dist/types/adapters/devices/junos/index.d.ts +0 -42
- package/dist/types/adapters/devices/junos/render.d.ts +0 -52
- package/dist/types/adapters/devices/lines.d.ts +0 -56
- package/dist/types/adapters/devices/raisecom-ros/index.d.ts +0 -28
- package/dist/types/adapters/devices/routeros/export.d.ts +0 -39
- package/dist/types/adapters/devices/routeros/index.d.ts +0 -30
- package/dist/types/adapters/devices/routeros/plan.d.ts +0 -4
- package/dist/types/adapters/devices/routeros/render.d.ts +0 -100
- package/dist/types/adapters/devices/types.d.ts +0 -40
- package/dist/types/adapters/devices/vrp/index.d.ts +0 -27
- package/dist/types/adapters/registries/index.d.ts +0 -3
- package/dist/types/adapters/registries/librenms.d.ts +0 -15
- package/dist/types/adapters/registries/peeringdb.d.ts +0 -16
- package/dist/types/adapters/registries/prometheus.d.ts +0 -16
- package/dist/types/core/across.d.ts +0 -4
- package/dist/types/core/addr.d.ts +0 -34
- package/dist/types/core/files.d.ts +0 -6
- package/dist/types/core/merge.d.ts +0 -4
- package/dist/types/core/time.d.ts +0 -2
- package/dist/types/core/validate.d.ts +0 -2
- package/dist/types/presets/index.d.ts +0 -183
- package/src/adapters/devices/catalog.ts +0 -41
- package/src/adapters/devices/derive.ts +0 -59
- package/src/adapters/devices/fortios/firewall.ts +0 -362
- package/src/adapters/devices/fortios/index.ts +0 -923
- package/src/adapters/devices/fortios/names.ts +0 -115
- package/src/adapters/devices/fortios/plan.ts +0 -888
- package/src/adapters/devices/fortios/render.ts +0 -768
- package/src/adapters/devices/fortios/routing.ts +0 -444
- package/src/adapters/devices/fortios/tree.ts +0 -121
- package/src/adapters/devices/index.ts +0 -9
- package/src/adapters/devices/junos/bgp.ts +0 -269
- package/src/adapters/devices/junos/index.ts +0 -862
- package/src/adapters/devices/junos/render.ts +0 -872
- package/src/adapters/devices/lines.ts +0 -212
- package/src/adapters/devices/raisecom-ros/TRAPS.md +0 -26
- package/src/adapters/devices/raisecom-ros/index.ts +0 -700
- package/src/adapters/devices/routeros/export.ts +0 -321
- package/src/adapters/devices/routeros/index.ts +0 -346
- package/src/adapters/devices/routeros/plan.ts +0 -398
- package/src/adapters/devices/routeros/render.ts +0 -1490
- package/src/adapters/devices/types.ts +0 -38
- package/src/adapters/devices/vrp/TRAPS.md +0 -26
- package/src/adapters/devices/vrp/index.ts +0 -865
- package/src/adapters/registries/index.ts +0 -19
- package/src/adapters/registries/librenms.ts +0 -92
- package/src/adapters/registries/peeringdb.ts +0 -169
- package/src/adapters/registries/prometheus.ts +0 -71
- package/src/cli/graph.ts +0 -89
- package/src/core/across.ts +0 -350
- package/src/core/addr.ts +0 -174
- package/src/core/addresses.ts +0 -316
- package/src/core/files.ts +0 -32
- package/src/core/graph.ts +0 -640
- package/src/core/merge.ts +0 -19
- package/src/core/time.ts +0 -15
- package/src/core/validate.ts +0 -348
- package/src/presets/index.ts +0 -579
- /package/dist/types/{adapters/devices → platforms}/fortios/models.d.ts +0 -0
- /package/dist/types/{adapters/devices → platforms}/junos/models.d.ts +0 -0
- /package/dist/types/{adapters/devices → platforms}/raisecom-ros/models.d.ts +0 -0
- /package/dist/types/{adapters/devices → platforms}/vrp/models.d.ts +0 -0
- /package/src/{adapters/devices → platforms}/fortios/models.ts +0 -0
- /package/src/{adapters/devices → platforms}/junos/models.ts +0 -0
- /package/src/{adapters/devices → platforms}/raisecom-ros/models.ts +0 -0
- /package/src/{adapters/devices → platforms}/vrp/models.ts +0 -0
package/dist/presets/index.js
DELETED
|
@@ -1,394 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
contains2
|
|
3
|
-
} from "../chunks/index-v8zgr7wm.js";
|
|
4
|
-
|
|
5
|
-
// src/presets/index.ts
|
|
6
|
-
var MARTIANS = ["127.0.0.0/8", "169.254.0.0/16", "0.0.0.0/8"];
|
|
7
|
-
var PRIVATE_RANGES = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"];
|
|
8
|
-
var antiSpoofing = (vlan, sources) => sources.map((src) => ({
|
|
9
|
-
description: `${vlan}: drop source ${src}`,
|
|
10
|
-
match: { vlan, src },
|
|
11
|
-
action: "drop"
|
|
12
|
-
}));
|
|
13
|
-
var AMPLIFIERS = {
|
|
14
|
-
qotd: 17,
|
|
15
|
-
chargen: 19,
|
|
16
|
-
dns: 53,
|
|
17
|
-
portmap: 111,
|
|
18
|
-
ntp: 123,
|
|
19
|
-
netbios: 137,
|
|
20
|
-
snmp: 161,
|
|
21
|
-
cldap: 389,
|
|
22
|
-
slp: 427,
|
|
23
|
-
rip: 520,
|
|
24
|
-
"ms-sql": 1434,
|
|
25
|
-
ssdp: 1900,
|
|
26
|
-
ard: 3283,
|
|
27
|
-
"ws-discovery": 3702,
|
|
28
|
-
mdns: 5353,
|
|
29
|
-
coap: 5683,
|
|
30
|
-
ubiquiti: 10001,
|
|
31
|
-
memcached: 11211,
|
|
32
|
-
dvr: 37810
|
|
33
|
-
};
|
|
34
|
-
var ASKED = new Set([AMPLIFIERS.dns, AMPLIFIERS.ntp, AMPLIFIERS.snmp]);
|
|
35
|
-
function antiAmplification(destinations, options = {}) {
|
|
36
|
-
return destinations.flatMap((dst) => [
|
|
37
|
-
...(options.keep_fragments ?? []).filter((prefix) => contains2(dst, prefix)).map((prefix) => ({
|
|
38
|
-
description: `UDP fragments to ${prefix} kept`,
|
|
39
|
-
match: { protocol: "udp", dst: prefix, src_port: 0 },
|
|
40
|
-
action: "accept"
|
|
41
|
-
})),
|
|
42
|
-
{ description: `UDP fragments to ${dst}`, match: { protocol: "udp", dst, src_port: 0 }, action: "drop" },
|
|
43
|
-
...Object.entries(AMPLIFIERS).flatMap(([name, port]) => ASKED.has(port) ? [
|
|
44
|
-
{
|
|
45
|
-
description: `UDP to ${dst} from ${name}, between two servers`,
|
|
46
|
-
match: { protocol: "udp", dst, src_port: port, dst_port: port },
|
|
47
|
-
action: "accept"
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
description: `UDP to ${dst} from ${name}, to a port below 1024`,
|
|
51
|
-
match: { protocol: "udp", dst, src_port: port, dst_port: { min: 0, max: 1023 } },
|
|
52
|
-
action: "drop"
|
|
53
|
-
}
|
|
54
|
-
] : [{ description: `UDP to ${dst} from ${name}`, match: { protocol: "udp", dst, src_port: port }, action: "drop" }])
|
|
55
|
-
]);
|
|
56
|
-
}
|
|
57
|
-
var BAD_TCP_FLAGS = [
|
|
58
|
-
["FIN+SYN", ["fin", "syn"], []],
|
|
59
|
-
["SYN+RST", ["syn", "rst"], []],
|
|
60
|
-
["FIN+RST", ["fin", "rst"], []],
|
|
61
|
-
["FIN without ACK", ["fin"], ["ack"]],
|
|
62
|
-
["FIN+URG", ["fin", "urg"], []],
|
|
63
|
-
["Xmas scan", ["fin", "syn", "psh", "urg"], []]
|
|
64
|
-
];
|
|
65
|
-
var badTcpFlags = () => BAD_TCP_FLAGS.map(([name, set, unset]) => ({
|
|
66
|
-
description: `Bad flags ${name}`,
|
|
67
|
-
match: { protocol: "tcp", tcp_flags: { set, unset } },
|
|
68
|
-
action: "drop"
|
|
69
|
-
}));
|
|
70
|
-
function bgpSanity(lengths = {}) {
|
|
71
|
-
const ipv4 = lengths.ipv4 ?? { min: 8, max: 24 };
|
|
72
|
-
const ipv6 = lengths.ipv6 ?? { min: 16, max: 48 };
|
|
73
|
-
return [
|
|
74
|
-
{
|
|
75
|
-
description: `IPv4 shorter than /${ipv4.min}`,
|
|
76
|
-
match: { family: "ipv4", prefix_length: { max: ipv4.min - 1 } },
|
|
77
|
-
action: "reject"
|
|
78
|
-
},
|
|
79
|
-
{ description: `IPv4 longer than /${ipv4.max}`, match: { family: "ipv4", prefix_length: { min: ipv4.max + 1 } }, action: "reject" },
|
|
80
|
-
{
|
|
81
|
-
description: `IPv6 shorter than /${ipv6.min}`,
|
|
82
|
-
match: { family: "ipv6", prefix_length: { max: ipv6.min - 1 } },
|
|
83
|
-
action: "reject"
|
|
84
|
-
},
|
|
85
|
-
{ description: `IPv6 longer than /${ipv6.max}`, match: { family: "ipv6", prefix_length: { min: ipv6.max + 1 } }, action: "reject" },
|
|
86
|
-
{ description: "RPKI invalid", match: { rpki: "invalid" }, action: "reject" }
|
|
87
|
-
];
|
|
88
|
-
}
|
|
89
|
-
function neighborPolicies(device) {
|
|
90
|
-
const bgp = device.routing?.bgp;
|
|
91
|
-
return Object.entries(bgp?.neighbors ?? {}).map(([name, neighbor]) => {
|
|
92
|
-
const group = neighbor.group ? bgp?.groups?.[neighbor.group] : undefined;
|
|
93
|
-
return {
|
|
94
|
-
name,
|
|
95
|
-
address: neighbor.address,
|
|
96
|
-
role: neighbor.role ?? group?.role,
|
|
97
|
-
import: neighbor.import ?? group?.import,
|
|
98
|
-
export: neighbor.export ?? group?.export
|
|
99
|
-
};
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
function offered(device, policy) {
|
|
103
|
-
const rules = policy ? device.policies?.[policy] ?? [] : [];
|
|
104
|
-
return rules.filter((rule) => rule.action === "accept" && rule.match?.prefix).map((rule) => rule.match.prefix);
|
|
105
|
-
}
|
|
106
|
-
var exportsEndInReject = (devices) => {
|
|
107
|
-
const findings = [];
|
|
108
|
-
for (const device of devices) {
|
|
109
|
-
for (const neighbor of neighborPolicies(device)) {
|
|
110
|
-
if (neighbor.role === "customer")
|
|
111
|
-
continue;
|
|
112
|
-
const last = neighbor.export ? device.policies?.[neighbor.export]?.at(-1) : undefined;
|
|
113
|
-
if (neighbor.export && (last?.action !== "reject" || last.match)) {
|
|
114
|
-
findings.push({
|
|
115
|
-
level: "error",
|
|
116
|
-
device: device.name,
|
|
117
|
-
message: `${neighbor.name}: export ${neighbor.export} does not end in an unconditional reject`
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
return findings;
|
|
123
|
-
};
|
|
124
|
-
var vlansOf = (port) => [port.access_vlan, ...port.trunk_vlans ?? []].filter((vlan) => vlan !== undefined);
|
|
125
|
-
var trustBoundary = (boundary) => (devices) => {
|
|
126
|
-
const untrusted = new Set(boundary.untrusted);
|
|
127
|
-
const routers = new Set(boundary.routers);
|
|
128
|
-
const extended = (a, b) => (boundary.extended ?? []).some(([x, y]) => x === a && y === b || x === b && y === a);
|
|
129
|
-
const findings = [];
|
|
130
|
-
for (const device of devices) {
|
|
131
|
-
const isRouter = routers.has(device.name);
|
|
132
|
-
const ports = Object.entries(device.ports ?? {}).flatMap(([name, port]) => port ? [{ name, port }] : []);
|
|
133
|
-
const carriers = [
|
|
134
|
-
...ports.filter(({ port }) => !port.lag).map(({ name, port }) => ({
|
|
135
|
-
what: `port ${name}`,
|
|
136
|
-
carried: vlansOf(port),
|
|
137
|
-
faces: port.link ? [port.link.device] : []
|
|
138
|
-
})),
|
|
139
|
-
...Object.entries(device.interfaces ?? {}).flatMap(([name, iface]) => iface.type === "lag" ? [
|
|
140
|
-
{
|
|
141
|
-
what: `LAG ${name}`,
|
|
142
|
-
carried: vlansOf(iface),
|
|
143
|
-
faces: ports.filter(({ port }) => port.lag === name && port.link).map(({ port }) => port.link.device)
|
|
144
|
-
}
|
|
145
|
-
] : [])
|
|
146
|
-
];
|
|
147
|
-
for (const { what, carried, faces } of carriers) {
|
|
148
|
-
const mixes = carried.some((vlan) => untrusted.has(vlan)) && carried.some((vlan) => !untrusted.has(vlan));
|
|
149
|
-
const facesRouter = isRouter || faces.some((name) => routers.has(name));
|
|
150
|
-
const isExtension = faces.length > 0 && faces.every((name) => extended(device.name, name));
|
|
151
|
-
if (mixes && !facesRouter && !isExtension) {
|
|
152
|
-
findings.push({
|
|
153
|
-
level: "error",
|
|
154
|
-
device: device.name,
|
|
155
|
-
message: `${what} carries an untrusted VLAN beside a trusted one and does not face a router`
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (isRouter)
|
|
160
|
-
continue;
|
|
161
|
-
for (const [name, iface] of Object.entries(device.interfaces ?? {})) {
|
|
162
|
-
if (iface.type === "vlan" && untrusted.has(iface.vlan)) {
|
|
163
|
-
findings.push({
|
|
164
|
-
level: "error",
|
|
165
|
-
device: device.name,
|
|
166
|
-
message: `interface ${name} puts an address on untrusted VLAN ${iface.vlan}; only a router may`
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return findings;
|
|
172
|
-
};
|
|
173
|
-
var tunnelsOutsideOffered = (devices) => {
|
|
174
|
-
const findings = [];
|
|
175
|
-
for (const device of devices) {
|
|
176
|
-
for (const [name, iface] of Object.entries(device.interfaces ?? {})) {
|
|
177
|
-
if (iface.type !== "gre" && iface.type !== "vxlan")
|
|
178
|
-
continue;
|
|
179
|
-
const subnets = (iface.addresses ?? []).map((entry) => typeof entry === "string" ? entry : entry.address);
|
|
180
|
-
for (const neighbor of neighborPolicies(device)) {
|
|
181
|
-
if (!subnets.some((subnet) => contains2(subnet, neighbor.address)))
|
|
182
|
-
continue;
|
|
183
|
-
for (const prefix of offered(device, neighbor.export)) {
|
|
184
|
-
if (contains2(prefix, iface.local)) {
|
|
185
|
-
findings.push({
|
|
186
|
-
level: "error",
|
|
187
|
-
device: device.name,
|
|
188
|
-
message: `${name} is sourced from ${iface.local}, inside ${prefix}, which ${neighbor.name} is offered`
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return findings;
|
|
196
|
-
};
|
|
197
|
-
var PREPENDS = [
|
|
198
|
-
["once", 1],
|
|
199
|
-
["twice", 2],
|
|
200
|
-
["three_times", 3]
|
|
201
|
-
];
|
|
202
|
-
var article = (word) => /^[aeiou]/i.test(word) ? `an ${word}` : `a ${word}`;
|
|
203
|
-
function communityScheme(scheme) {
|
|
204
|
-
const { asn } = scheme;
|
|
205
|
-
const community = (fn, parameter) => `${asn}:${fn}:${parameter}`;
|
|
206
|
-
const ours = { standard: [`${asn}:*`], large: [`${asn}:*:*`] };
|
|
207
|
-
const information = [scheme.learned_from?.function, scheme.learned_at?.function, scheme.learned_from_as].filter((fn) => fn !== undefined);
|
|
208
|
-
const tag = (neighborClass, neighborAs, options = {}) => {
|
|
209
|
-
const { site, trusted = false } = options;
|
|
210
|
-
if (scheme.learned_at && site === undefined)
|
|
211
|
-
throw new Error(`communityScheme: tag for AS${neighborAs} needs a site, for learned_at`);
|
|
212
|
-
return {
|
|
213
|
-
description: `Learned from AS${neighborAs}`,
|
|
214
|
-
set: {
|
|
215
|
-
remove_communities: ours.standard,
|
|
216
|
-
remove_large_communities: trusted ? information.map((fn) => community(fn, "*")) : ours.large,
|
|
217
|
-
add_large_communities: [
|
|
218
|
-
...scheme.learned_from ? [community(scheme.learned_from.function, scheme.learned_from.classes[neighborClass])] : [],
|
|
219
|
-
...scheme.learned_at ? [community(scheme.learned_at.function, site)] : [],
|
|
220
|
-
...scheme.learned_from_as !== undefined ? [community(scheme.learned_from_as, neighborAs)] : []
|
|
221
|
-
]
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
};
|
|
225
|
-
const blackhole = (prefixSets) => {
|
|
226
|
-
const fn = scheme.blackhole?.function;
|
|
227
|
-
if (fn === undefined)
|
|
228
|
-
throw new Error("communityScheme: blackhole needs a function number in the scheme");
|
|
229
|
-
return prefixSets.map((prefixSet) => ({
|
|
230
|
-
description: "Blackhole, asked by the neighbor",
|
|
231
|
-
match: { large_community: community(fn, 0), prefix_set: prefixSet },
|
|
232
|
-
set: { blackhole: true },
|
|
233
|
-
action: "accept"
|
|
234
|
-
}));
|
|
235
|
-
};
|
|
236
|
-
const actions = (neighborAs) => {
|
|
237
|
-
const passOn = scheme.blackhole?.upstreams?.[neighborAs];
|
|
238
|
-
return [
|
|
239
|
-
...scheme.blackhole !== undefined && !passOn ? [
|
|
240
|
-
{
|
|
241
|
-
description: "Blackholed here, never announced",
|
|
242
|
-
match: { large_community: community(scheme.blackhole.function, 0) },
|
|
243
|
-
action: "reject"
|
|
244
|
-
}
|
|
245
|
-
] : [],
|
|
246
|
-
...scheme.do_not_announce !== undefined ? [
|
|
247
|
-
{
|
|
248
|
-
description: "Asked not to be announced anywhere",
|
|
249
|
-
match: { large_community: community(scheme.do_not_announce, 0) },
|
|
250
|
-
action: "reject"
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
description: `Asked not to be announced to AS${neighborAs}`,
|
|
254
|
-
match: { large_community: community(scheme.do_not_announce, neighborAs) },
|
|
255
|
-
action: "reject"
|
|
256
|
-
}
|
|
257
|
-
] : [],
|
|
258
|
-
...scheme.blackhole !== undefined && passOn ? [
|
|
259
|
-
{
|
|
260
|
-
description: `Blackhole passed on to AS${neighborAs}`,
|
|
261
|
-
match: { large_community: community(scheme.blackhole.function, 0) },
|
|
262
|
-
set: {
|
|
263
|
-
remove_communities: ours.standard,
|
|
264
|
-
remove_large_communities: ours.large,
|
|
265
|
-
add_communities: [passOn]
|
|
266
|
-
},
|
|
267
|
-
action: "accept"
|
|
268
|
-
}
|
|
269
|
-
] : [],
|
|
270
|
-
...PREPENDS.flatMap(([name, times]) => {
|
|
271
|
-
const fn = scheme.prepend?.[name];
|
|
272
|
-
if (fn === undefined)
|
|
273
|
-
return [];
|
|
274
|
-
return [
|
|
275
|
-
{
|
|
276
|
-
description: `Asked to prepend ${name.replace("_", " ")} to AS${neighborAs}`,
|
|
277
|
-
match: { large_community: community(fn, neighborAs) },
|
|
278
|
-
set: { prepend: times }
|
|
279
|
-
}
|
|
280
|
-
];
|
|
281
|
-
}),
|
|
282
|
-
{
|
|
283
|
-
description: "Our communities stay inside our network",
|
|
284
|
-
set: { remove_communities: ours.standard, remove_large_communities: ours.large }
|
|
285
|
-
}
|
|
286
|
-
];
|
|
287
|
-
};
|
|
288
|
-
const catalogue = [
|
|
289
|
-
...Object.entries(scheme.learned_from?.classes ?? {}).map(([name, value]) => ({
|
|
290
|
-
community: community(scheme.learned_from.function, value),
|
|
291
|
-
description: `Learned from ${article(name)}`
|
|
292
|
-
})),
|
|
293
|
-
...scheme.learned_at ? [
|
|
294
|
-
...Object.entries(scheme.learned_at.sites ?? {}).map(([site, name]) => ({
|
|
295
|
-
community: community(scheme.learned_at.function, site),
|
|
296
|
-
description: `Learned in ${name}`
|
|
297
|
-
})),
|
|
298
|
-
{ community: community(scheme.learned_at.function, "nnn"), description: "Learned at site $0" }
|
|
299
|
-
] : [],
|
|
300
|
-
...scheme.learned_from_as !== undefined ? [{ community: community(scheme.learned_from_as, "nnn"), description: "Learned from AS$0" }] : [],
|
|
301
|
-
...scheme.do_not_announce !== undefined ? [
|
|
302
|
-
{ community: community(scheme.do_not_announce, 0), description: "Do not announce to anyone" },
|
|
303
|
-
{ community: community(scheme.do_not_announce, "nnn"), description: "Do not announce to AS$0" }
|
|
304
|
-
] : [],
|
|
305
|
-
...PREPENDS.flatMap(([name]) => {
|
|
306
|
-
const fn = scheme.prepend?.[name];
|
|
307
|
-
return fn === undefined ? [] : [{ community: community(fn, "nnn"), description: `Prepend ${name.replace("_", " ")} to AS$0` }];
|
|
308
|
-
}),
|
|
309
|
-
...scheme.blackhole !== undefined ? [
|
|
310
|
-
{
|
|
311
|
-
community: community(scheme.blackhole.function, 0),
|
|
312
|
-
description: Object.keys(scheme.blackhole.upstreams ?? {}).length ? `Blackhole: dropped in AS${asn} and by its upstreams that take it` : `Blackhole: dropped in AS${asn}, not announced further`
|
|
313
|
-
}
|
|
314
|
-
] : []
|
|
315
|
-
];
|
|
316
|
-
return { community, tag, actions, blackhole, catalogue };
|
|
317
|
-
}
|
|
318
|
-
function internetExchange(exchange, members) {
|
|
319
|
-
const percent = exchange.storm_percent ?? 1;
|
|
320
|
-
const ports = (device) => {
|
|
321
|
-
const result = {};
|
|
322
|
-
for (const member of members) {
|
|
323
|
-
const port = member.ports[device];
|
|
324
|
-
if (!port)
|
|
325
|
-
continue;
|
|
326
|
-
result[port] = {
|
|
327
|
-
description: `${member.name}, AS${member.asn}`,
|
|
328
|
-
access_vlan: exchange.vlan,
|
|
329
|
-
stp: false,
|
|
330
|
-
lldp: false,
|
|
331
|
-
storm_control: { broadcast: { percent }, multicast: { percent }, unknown_unicast: { percent } }
|
|
332
|
-
};
|
|
333
|
-
}
|
|
334
|
-
return result;
|
|
335
|
-
};
|
|
336
|
-
const check = (devices) => {
|
|
337
|
-
const findings = [];
|
|
338
|
-
const error = (message, device) => findings.push({ level: "error", ...device ? { device } : {}, message });
|
|
339
|
-
const taken = new Map((exchange.reserved ?? []).map((address) => [address, "reserved"]));
|
|
340
|
-
const portHolders = new Map;
|
|
341
|
-
members.forEach((member, index) => {
|
|
342
|
-
for (const other of members.slice(index + 1)) {
|
|
343
|
-
if (other.name === member.name)
|
|
344
|
-
error(`member ${member.name} is declared twice`);
|
|
345
|
-
if (other.asn === member.asn)
|
|
346
|
-
error(`members ${member.name} and ${other.name} share AS${member.asn}`);
|
|
347
|
-
}
|
|
348
|
-
for (const [address, lan] of [
|
|
349
|
-
[member.ipv4, exchange.lan.ipv4],
|
|
350
|
-
[member.ipv6, exchange.lan.ipv6]
|
|
351
|
-
]) {
|
|
352
|
-
if (!address)
|
|
353
|
-
continue;
|
|
354
|
-
if (!lan || !contains2(lan, address))
|
|
355
|
-
error(`${address} of ${member.name} is outside the peering LAN`);
|
|
356
|
-
const holder = taken.get(address);
|
|
357
|
-
if (holder)
|
|
358
|
-
error(`${address} of ${member.name} is already ${holder === "reserved" ? "reserved" : `${holder}'s`}`);
|
|
359
|
-
taken.set(address, member.name);
|
|
360
|
-
}
|
|
361
|
-
for (const [deviceName, portName] of Object.entries(member.ports)) {
|
|
362
|
-
const holder = portHolders.get(`${deviceName} ${portName}`);
|
|
363
|
-
if (holder)
|
|
364
|
-
error(`port ${portName} is given to both ${holder} and ${member.name}`, deviceName);
|
|
365
|
-
portHolders.set(`${deviceName} ${portName}`, member.name);
|
|
366
|
-
const device = devices.find((candidate) => candidate.name === deviceName);
|
|
367
|
-
const port = device?.ports?.[portName];
|
|
368
|
-
const carried = port ? vlansOf(port) : [];
|
|
369
|
-
if (carried.length !== 1 || carried[0] !== exchange.vlan) {
|
|
370
|
-
error(`port ${portName} of ${member.name} does not carry the peering VLAN alone`, deviceName);
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
});
|
|
374
|
-
return findings;
|
|
375
|
-
};
|
|
376
|
-
return { ports, check };
|
|
377
|
-
}
|
|
378
|
-
export {
|
|
379
|
-
AMPLIFIERS,
|
|
380
|
-
MARTIANS,
|
|
381
|
-
PRIVATE_RANGES,
|
|
382
|
-
antiAmplification,
|
|
383
|
-
antiSpoofing,
|
|
384
|
-
badTcpFlags,
|
|
385
|
-
bgpSanity,
|
|
386
|
-
communityScheme,
|
|
387
|
-
exportsEndInReject,
|
|
388
|
-
internetExchange,
|
|
389
|
-
neighborPolicies,
|
|
390
|
-
offered,
|
|
391
|
-
trustBoundary,
|
|
392
|
-
tunnelsOutsideOffered,
|
|
393
|
-
vlansOf
|
|
394
|
-
};
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
export declare const catalog: {
|
|
2
|
-
readonly routeros: {
|
|
3
|
-
readonly "CCR2216-1G-12XS-2XQ": {
|
|
4
|
-
readonly ports: {
|
|
5
|
-
readonly "100g": 2;
|
|
6
|
-
readonly "25g": 12;
|
|
7
|
-
readonly "1g": 1;
|
|
8
|
-
};
|
|
9
|
-
readonly spelling: {
|
|
10
|
-
readonly "100g": "qsfp28-{n}-1";
|
|
11
|
-
readonly "25g": "sfp28-{n}";
|
|
12
|
-
readonly "1g": "ether{n}";
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
};
|
|
16
|
-
readonly vrp: {
|
|
17
|
-
readonly "CE6855-48S6Q-HI": {
|
|
18
|
-
readonly ports: {
|
|
19
|
-
readonly "10g": 48;
|
|
20
|
-
readonly "40g": 6;
|
|
21
|
-
};
|
|
22
|
-
readonly spelling: {
|
|
23
|
-
readonly "10g": "10GE1/0/{n}";
|
|
24
|
-
readonly "40g": "40GE1/0/{n}";
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
readonly "raisecom-ros": {
|
|
29
|
-
readonly "RAX721-C-6C48": {
|
|
30
|
-
readonly ports: {
|
|
31
|
-
readonly "100g": 6;
|
|
32
|
-
readonly "25g": 24;
|
|
33
|
-
readonly "10g": 24;
|
|
34
|
-
};
|
|
35
|
-
readonly spelling: {
|
|
36
|
-
readonly "100g": "hundredgige 1/1/{n}";
|
|
37
|
-
readonly "25g": "twenty-fivegige 1/2/{n}";
|
|
38
|
-
readonly "10g": "tengigabitethernet 1/3/{n}";
|
|
39
|
-
};
|
|
40
|
-
};
|
|
41
|
-
};
|
|
42
|
-
readonly junos: {
|
|
43
|
-
readonly "QFX5100-48S-6Q": {
|
|
44
|
-
readonly ports: {
|
|
45
|
-
readonly "40g": 6;
|
|
46
|
-
readonly "10g": 48;
|
|
47
|
-
readonly "1g": 2;
|
|
48
|
-
};
|
|
49
|
-
readonly spelling: {
|
|
50
|
-
readonly "40g": "et-0/0/{n+47}";
|
|
51
|
-
readonly "10g": "xe-0/0/{n-1}";
|
|
52
|
-
readonly "1g": "em{n-1}";
|
|
53
|
-
};
|
|
54
|
-
};
|
|
55
|
-
};
|
|
56
|
-
readonly fortios: {
|
|
57
|
-
readonly "FG-3700D": {
|
|
58
|
-
readonly ports: {
|
|
59
|
-
readonly "40g": 4;
|
|
60
|
-
readonly "10g": 28;
|
|
61
|
-
readonly "1g": 2;
|
|
62
|
-
};
|
|
63
|
-
readonly spelling: {
|
|
64
|
-
readonly "40g": "port{n}";
|
|
65
|
-
readonly "10g": "port{n+4}";
|
|
66
|
-
readonly "1g": "mgmt{n}";
|
|
67
|
-
};
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
};
|
|
71
|
-
export type Catalog = typeof catalog;
|
|
72
|
-
export type PlatformName = keyof Catalog;
|
|
73
|
-
export type ModelName<Pl extends PlatformName> = keyof Catalog[Pl] & string;
|
|
74
|
-
type Upto<N extends number, A extends unknown[] = [], R = never> = A["length"] extends N ? R : Upto<N, [...A, 0], R | `${[...A, 0]["length"]}`>;
|
|
75
|
-
type PortsOf<Pl extends PlatformName, M extends ModelName<Pl>> = Catalog[Pl][M] extends {
|
|
76
|
-
ports: infer P;
|
|
77
|
-
} ? P : never;
|
|
78
|
-
/** `10g-1` to `10g-48` on a model with 48 10G ports. */
|
|
79
|
-
export type PortName<Pl extends PlatformName, M extends ModelName<Pl>> = {
|
|
80
|
-
[S in keyof PortsOf<Pl, M>]: `${S & string}-${Upto<PortsOf<Pl, M>[S] & number>}`;
|
|
81
|
-
}[keyof PortsOf<Pl, M>];
|
|
82
|
-
/** Every port a model has, in order. */
|
|
83
|
-
export declare function portsOf(platform: string, model: string): string[];
|
|
84
|
-
/** The platform's own name for a port. */
|
|
85
|
-
export declare function spell(platform: string, model: string, port: string): string;
|
|
86
|
-
export {};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Device } from "../../schema";
|
|
2
|
-
/** Each LAG's number: its own `id`, or its position among the device's LAGs. */
|
|
3
|
-
export declare function lagIds(device: Device): Map<string, number>;
|
|
4
|
-
/** The IPv4 networks of a port's or an interface's addresses. */
|
|
5
|
-
export declare function ipv4Networks(device: Device, iface: string): string[];
|
|
6
|
-
/** Fields neither switch platform, VRP nor Raisecom ROS, expresses: a service's own sources or port, a user's description or keys, the IP stack's host settings, a point-to-point address, and offload per interface. */
|
|
7
|
-
export declare function switchUnsupported(device: Device): string[];
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { AclRule, Device, Family, FilterMatch, FilterRule, NatRule, Ports, Protocol } from "../../../schema";
|
|
2
|
-
import { Block } from "./tree";
|
|
3
|
-
/** IP protocol numbers, for a protocol the platform names only by number. */
|
|
4
|
-
export declare const PROTOCOL_NUMBER: Record<Protocol, number>;
|
|
5
|
-
/** NAT rules of both directions, which central NAT needs turned on. */
|
|
6
|
-
export declare function natRules(device: Device): NatRule<string, string>[];
|
|
7
|
-
/** Which families a rule applies to: its own, its addresses', or both. */
|
|
8
|
-
export declare function familiesOf(device: Device, match: FilterMatch<string, string> | undefined): Family[];
|
|
9
|
-
/** A port or ports as the platform writes them in a service: `22`, `1000-2000`. */
|
|
10
|
-
export declare function portList(ports: Ports | undefined): string[];
|
|
11
|
-
/** Every protocol, as a service of Circuit's own, for a device in transparent mode. */
|
|
12
|
-
export declare const ALL_IN_TRANSPARENT = "circuit-all";
|
|
13
|
-
/** The service a rule matches, by name, with what it holds. `ALL` when the rule names no protocol and no port; ports without a protocol are TCP's and UDP's. */
|
|
14
|
-
export declare function serviceOf(match: FilterMatch<string, string> | undefined, family: Family): {
|
|
15
|
-
name: string;
|
|
16
|
-
block?: Block;
|
|
17
|
-
};
|
|
18
|
-
/** A rule the platform keeps without being told: replies to a session it let through, and packets that belong to one, pass on their own. */
|
|
19
|
-
export declare function isImplied(rule: FilterRule<string, string>): boolean;
|
|
20
|
-
/** Packet filtering, who reaches the device, NAT and stateless ACLs. */
|
|
21
|
-
export declare function firewall(root: Block, device: Device): void;
|
|
22
|
-
/** Whether a port's ACL drops before it accepts: an accept before a drop is an exception the platform's ACLs cannot hold. */
|
|
23
|
-
export declare function acceptsBeforeDrop(rules: readonly AclRule<string>[]): boolean;
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import type { Client } from "ssh2";
|
|
2
|
-
import type { Device, Family } from "../../../schema";
|
|
3
|
-
import { type ConsoleDialect } from "../../../transport/console";
|
|
4
|
-
import type { ApplyOptions, DeviceAdapter, Plan, ReadOptions } from "../types";
|
|
5
|
-
/** What a session reads and writes: an SSH shell, or anything else that streams the CLI. */
|
|
6
|
-
export type Channel = {
|
|
7
|
-
write(data: string): unknown;
|
|
8
|
-
on(event: "data", listener: (chunk: Buffer) => void): unknown;
|
|
9
|
-
on(event: "close", listener: () => void): unknown;
|
|
10
|
-
removeListener(event: "data", listener: (chunk: Buffer) => void): unknown;
|
|
11
|
-
removeListener(event: "close", listener: () => void): unknown;
|
|
12
|
-
};
|
|
13
|
-
/** A CLI over a channel: one line at a time, and what the device printed until its prompt came back. */
|
|
14
|
-
export declare class Cli {
|
|
15
|
-
private readonly channel;
|
|
16
|
-
private readonly newline;
|
|
17
|
-
/** The prompt that ended the last answer, which shows where the session is: `(port1)` inside an entry. */
|
|
18
|
-
prompt: string;
|
|
19
|
-
constructor(channel: Channel, newline?: string);
|
|
20
|
-
/** Wait for the prompt, after logging in. */
|
|
21
|
-
ready(timeout?: number): Promise<void>;
|
|
22
|
-
/** Send one line and return what the device printed after it, without the echo or the prompt. */
|
|
23
|
-
run(line: string, timeout?: number): Promise<string>;
|
|
24
|
-
/** Answer a question the device asked. */
|
|
25
|
-
answer(reply: "y" | "n", timeout?: number): Promise<string>;
|
|
26
|
-
/** What the device prints until its prompt or a question. A session the device ended, or that went silent, fails. */
|
|
27
|
-
private collect;
|
|
28
|
-
}
|
|
29
|
-
export declare function login(device: Device): Promise<Client>;
|
|
30
|
-
/** How the FortiOS console asks for a login, and what moves it on from where the last session left it. */
|
|
31
|
-
export declare const FORTIOS_CONSOLE: ConsoleDialect;
|
|
32
|
-
/** Refuse a device on a release this adapter was not proved on, before anything is read or sent. */
|
|
33
|
-
export declare function checkVersion(cli: Cli, device: Device): Promise<void>;
|
|
34
|
-
/** Secrets the device prints: a password or an SNMPv3 key as a cipher, a certificate's key encrypted, and the SNMP community in clear. None leave the read. */
|
|
35
|
-
export declare function scrub(text: string): string;
|
|
36
|
-
/** Every section Circuit manages, as the device holds it, credentials scrubbed. */
|
|
37
|
-
export declare function readConfig(cli: Cli, device: Device): Promise<string>;
|
|
38
|
-
export declare function read(device: Device, _network?: readonly Device[], options?: ReadOptions): Promise<string>;
|
|
39
|
-
/**
|
|
40
|
-
* A line with each secret's value in place, escaped inside its quotes. A certificate's key from a variable is PEM encoded as one line of base64, and is sent as the PEM it holds. A file saved with Windows line endings is sent with plain ones: the CLI takes each carriage return as a line of its own, and refuses the key, `Invalid private key`. A `?`, which the CLI takes as a call for help, is typed literally.
|
|
41
|
-
*/
|
|
42
|
-
export declare function withSecrets(line: string): string;
|
|
43
|
-
/** How a change that could cut access is guarded: the device reloads its saved configuration after `seconds` unless `prove` shows access survived. */
|
|
44
|
-
export type Guard = {
|
|
45
|
-
seconds: number;
|
|
46
|
-
prove: () => Promise<void>;
|
|
47
|
-
};
|
|
48
|
-
/**
|
|
49
|
-
* Send a plan line by line, each applied as it arrives. The device is first set to revert what is not saved, so a refused line or a fresh login that fails reloads its saved configuration. Once access is proved the change is saved, and changes save themselves again.
|
|
50
|
-
*/
|
|
51
|
-
export declare function configure(cli: Cli, plan: Plan, guard: Guard): Promise<void>;
|
|
52
|
-
export declare function apply(device: Device, network: readonly Device[], changes: Plan, options: ApplyOptions): Promise<void>;
|
|
53
|
-
/** The lines that replace a prefix list's entries with what a registry returned: every entry is purged, then each prefix added, matching it and anything more specific. */
|
|
54
|
-
export declare function fillLines(set: string, family: Family, prefixes: string[]): string[];
|
|
55
|
-
/** Replace a prefix list `refresh` fetched. It cannot cut access, so it is sent without a guard, and saved as it goes. `purge` asks to confirm, and is answered yes. */
|
|
56
|
-
export declare function fill(device: Device, _network: readonly Device[], set: string, family: Family, prefixes: string[]): Promise<void>;
|
|
57
|
-
export declare function unsupported(device: Device): string[];
|
|
58
|
-
export declare const fortios: DeviceAdapter;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { Device, Family } from "../../../schema";
|
|
2
|
-
type Addressed = {
|
|
3
|
-
addresses?: readonly (string | {
|
|
4
|
-
address: string;
|
|
5
|
-
peer?: string;
|
|
6
|
-
})[];
|
|
7
|
-
vrf?: string;
|
|
8
|
-
lag?: string;
|
|
9
|
-
};
|
|
10
|
-
/** The bridges a device has, in the config's order. A device with any runs in transparent mode, each bridge a forward domain numbered by its place. */
|
|
11
|
-
export declare function bridgesOf(device: Device): {
|
|
12
|
-
name: string;
|
|
13
|
-
members: readonly string[];
|
|
14
|
-
}[];
|
|
15
|
-
/** Whether the device runs in transparent mode: it has a bridge. */
|
|
16
|
-
export declare const isTransparent: (device: Device) => boolean;
|
|
17
|
-
/**
|
|
18
|
-
* The management address of a device in transparent mode: the one IPv4 address on a port or an interface outside every bridge. The device answers on it, the platform's `manageip`, through that interface alone. Undefined when there is none, and the device is reached only through its console.
|
|
19
|
-
*/
|
|
20
|
-
export declare function transparentManagement(device: Device): {
|
|
21
|
-
name: string;
|
|
22
|
-
address: string;
|
|
23
|
-
} | undefined;
|
|
24
|
-
/** The forward domain of a VLAN interface in a bridge, or undefined. */
|
|
25
|
-
export declare function forwardDomainOf(device: Device, name: string): number | undefined;
|
|
26
|
-
/** The name the platform gives a port or an interface: a port by its spelling, any other interface by its key. */
|
|
27
|
-
export declare function nameOf(device: Device, name: string): string;
|
|
28
|
-
/** A port's or an interface's settings, by its key. */
|
|
29
|
-
export declare function settingsOf(device: Device, name: string): Addressed | undefined;
|
|
30
|
-
/** Every address of a port or an interface. */
|
|
31
|
-
export declare function addressesOf(settings: Addressed | undefined): string[];
|
|
32
|
-
/** An address or prefix with its length, a bare address taken as a host. */
|
|
33
|
-
export declare const withLength: (value: string) => string;
|
|
34
|
-
/** The family of an address or prefix. */
|
|
35
|
-
export declare const familyOfPrefix: (value: string) => Family;
|
|
36
|
-
/** `192.0.2.0 255.255.255.0`, how the platform writes an IPv4 prefix. */
|
|
37
|
-
export declare const subnet: (prefix: string) => string;
|
|
38
|
-
/** The canonical form of a prefix: its network address and length, a bare address taken as a host. */
|
|
39
|
-
export declare const network: (prefix: string) => string;
|
|
40
|
-
/** The number of a VRF on the platform: its place among the device's VRFs, the default table being 0. */
|
|
41
|
-
export declare function vrfNumber(device: Device, vrf: string | undefined): number;
|
|
42
|
-
/** The interface whose own network holds an address, the most specific when several do, in one routing table. */
|
|
43
|
-
export declare function interfaceFor(device: Device, address: string, vrf?: string): string | undefined;
|
|
44
|
-
/** The interface that holds an address as its own. */
|
|
45
|
-
export declare function holderOf(device: Device, address: string): string | undefined;
|
|
46
|
-
/** Every port and interface with an address, by key, where the device's services answer. */
|
|
47
|
-
export declare function addressed(device: Device): string[];
|
|
48
|
-
export {};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { ApplyOptions, Plan } from "../types";
|
|
2
|
-
import { Block } from "./tree";
|
|
3
|
-
/** How the plan treats the entries of one table. */
|
|
4
|
-
type Table = {
|
|
5
|
-
/** Entries the factory holds. The plan neither reads nor removes them. */
|
|
6
|
-
factory?: readonly string[];
|
|
7
|
-
/** The device keeps the entries in an order of their own, which `move` changes. */
|
|
8
|
-
ordered?: true;
|
|
9
|
-
/** An entry is known by what it holds, not by its number. */
|
|
10
|
-
byContent?: true;
|
|
11
|
-
/** Settings the device gives an entry it creates. They are unset when the render does not hold them. */
|
|
12
|
-
created?: (entry: Block) => readonly string[];
|
|
13
|
-
/** Settings an entry keeps for life. A change deletes the entry and creates it again. */
|
|
14
|
-
fixed?: readonly string[];
|
|
15
|
-
/** The device refuses an entry that holds the same as another, `Duplicated entry`, even for a moment while entries are renumbered. */
|
|
16
|
-
distinct?: true;
|
|
17
|
-
};
|
|
18
|
-
/** Tables whose entries need more than a plain comparison, by section. */
|
|
19
|
-
export declare const TABLES: Record<string, Table>;
|
|
20
|
-
/** The configuration as the plan reads it: factory entries and the device's own settings left out. */
|
|
21
|
-
export declare function clean(text: string): string;
|
|
22
|
-
/**
|
|
23
|
-
* What changes, by section, in the order the render lists them. Entries that go are deleted after everything else, in the reverse order, so nothing is deleted while another section still names it.
|
|
24
|
-
*
|
|
25
|
-
* A secret is sent when its entry is new, or with `secrets` set; it cannot be read back to compare.
|
|
26
|
-
*/
|
|
27
|
-
export declare function plan(desired: string, current: string, options: Pick<ApplyOptions, "secrets">): Plan;
|
|
28
|
-
export {};
|