@takodotid/circuit 0.4.3
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/LICENSE +106 -0
- package/README.md +195 -0
- package/package.json +83 -0
- package/src/adapters/devices/catalog.ts +38 -0
- package/src/adapters/devices/derive.ts +27 -0
- package/src/adapters/devices/index.ts +7 -0
- package/src/adapters/devices/lines.ts +212 -0
- package/src/adapters/devices/raisecom-ros/TRAPS.md +22 -0
- package/src/adapters/devices/raisecom-ros/index.ts +603 -0
- package/src/adapters/devices/raisecom-ros/models.ts +7 -0
- package/src/adapters/devices/routeros/TRAPS.md +33 -0
- package/src/adapters/devices/routeros/export.ts +319 -0
- package/src/adapters/devices/routeros/index.ts +261 -0
- package/src/adapters/devices/routeros/models.ts +8 -0
- package/src/adapters/devices/routeros/plan.ts +370 -0
- package/src/adapters/devices/routeros/render.ts +1431 -0
- package/src/adapters/devices/types.ts +31 -0
- package/src/adapters/devices/vrp/TRAPS.md +22 -0
- package/src/adapters/devices/vrp/index.ts +742 -0
- package/src/adapters/devices/vrp/models.ts +4 -0
- package/src/adapters/registries/index.ts +19 -0
- package/src/adapters/registries/peeringdb.ts +169 -0
- package/src/cli/index.ts +295 -0
- package/src/core/addr.ts +145 -0
- package/src/core/define.ts +94 -0
- package/src/core/secrets.ts +68 -0
- package/src/core/time.ts +15 -0
- package/src/core/validate.ts +380 -0
- package/src/index.ts +6 -0
- package/src/schema/common.ts +32 -0
- package/src/schema/device.ts +95 -0
- package/src/schema/firewall.ts +128 -0
- package/src/schema/index.ts +7 -0
- package/src/schema/interfaces.ts +192 -0
- package/src/schema/policy.ts +88 -0
- package/src/schema/routing.ts +120 -0
- package/src/schema/system.ts +191 -0
- package/src/transport/ssh.ts +125 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { IP } from "./common";
|
|
2
|
+
import type { AclRule, Firewall } from "./firewall";
|
|
3
|
+
import type { Interface, Port, Vlan } from "./interfaces";
|
|
4
|
+
import type { PrefixSet, RoutePolicy } from "./policy";
|
|
5
|
+
import type { Routing } from "./routing";
|
|
6
|
+
import type { Certificate, DhcpRelay, DhcpServer, FlowExport, Management, System, User } from "./system";
|
|
7
|
+
|
|
8
|
+
/** How the framework reaches the device. */
|
|
9
|
+
export type Connection<U extends string> = {
|
|
10
|
+
/** Management address. */
|
|
11
|
+
host: IP;
|
|
12
|
+
/** One of the device's `users`. Its password is the login. */
|
|
13
|
+
user: U;
|
|
14
|
+
/** SSH port. 22 when absent. */
|
|
15
|
+
port?: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/** A separate routing table, with the interfaces that route in it. */
|
|
19
|
+
export type Vrf = {
|
|
20
|
+
/** What the VRF is for. */
|
|
21
|
+
description?: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Everything one device runs. What is not written here is removed from the device or returned to its default.
|
|
26
|
+
*
|
|
27
|
+
* Type parameters are the names the device declares, so a reference to a name that does not exist fails to compile: N ports, V VLANs, I interfaces, P policies, S prefix sets, G BGP groups, A ACLs, AS address sets, U users, F VRFs, C certificates.
|
|
28
|
+
*/
|
|
29
|
+
export type Device<
|
|
30
|
+
Pl extends string = string,
|
|
31
|
+
M extends string = string,
|
|
32
|
+
N extends string = string,
|
|
33
|
+
V extends string = string,
|
|
34
|
+
I extends string = string,
|
|
35
|
+
P extends string = string,
|
|
36
|
+
S extends string = string,
|
|
37
|
+
G extends string = string,
|
|
38
|
+
A extends string = string,
|
|
39
|
+
AS extends string = string,
|
|
40
|
+
U extends string = string,
|
|
41
|
+
F extends string = string,
|
|
42
|
+
C extends string = string,
|
|
43
|
+
> = {
|
|
44
|
+
/** Hostname. */
|
|
45
|
+
name: string;
|
|
46
|
+
/** Operating system, which decides the adapter that renders and applies the device. */
|
|
47
|
+
platform: Pl;
|
|
48
|
+
/** Hardware model. Decides which port names exist. */
|
|
49
|
+
model: M;
|
|
50
|
+
/** How the framework logs in. */
|
|
51
|
+
connection: Connection<NoInfer<U>>;
|
|
52
|
+
/** Device-wide settings. */
|
|
53
|
+
system?: System;
|
|
54
|
+
/** Logins, keyed by user name. Users not listed are removed. */
|
|
55
|
+
users?: Record<U, User>;
|
|
56
|
+
/** Ways in, and who may use them. */
|
|
57
|
+
management?: Management<NoInfer<I | N>, NoInfer<C>>;
|
|
58
|
+
/** Certificates, keyed by name. */
|
|
59
|
+
certificates?: Record<C, Certificate>;
|
|
60
|
+
/** VLANs, keyed by name. */
|
|
61
|
+
vlans?: Record<V, Vlan>;
|
|
62
|
+
/** Physical ports, keyed by `<speed>-<position>`. */
|
|
63
|
+
ports?: Partial<Record<N, Port<NoInfer<V>, NoInfer<A>, NoInfer<I>, NoInfer<F>>>>;
|
|
64
|
+
/** Interfaces that are not physical ports, keyed by name. */
|
|
65
|
+
interfaces?: Record<I, Interface<NoInfer<V>, NoInfer<F>>>;
|
|
66
|
+
/** Separate routing tables, keyed by name. */
|
|
67
|
+
vrfs?: Record<F, Vrf>;
|
|
68
|
+
/** Static routes, BGP, OSPF and route validation. */
|
|
69
|
+
routing?: Routing<NoInfer<P>, G, NoInfer<I | N>, NoInfer<F>>;
|
|
70
|
+
/** Route policies, keyed by name. */
|
|
71
|
+
policies?: Record<P, RoutePolicy<NoInfer<P>, NoInfer<S>>>;
|
|
72
|
+
/** Prefix sets that policies match on, keyed by name. */
|
|
73
|
+
prefix_sets?: Record<S, PrefixSet>;
|
|
74
|
+
/** Packet filtering and address translation. */
|
|
75
|
+
firewall?: Firewall<NoInfer<I | N>, AS>;
|
|
76
|
+
/** Hardware ACLs, keyed by name, applied to a port with `acl`. */
|
|
77
|
+
acls?: Record<A, readonly AclRule<NoInfer<V>>[]>;
|
|
78
|
+
/** DHCP servers, keyed by name. */
|
|
79
|
+
dhcp?: Record<string, DhcpServer<NoInfer<I | N>>>;
|
|
80
|
+
/** DHCP relays, keyed by name. */
|
|
81
|
+
dhcp_relay?: Record<string, DhcpRelay<NoInfer<I | N>>>;
|
|
82
|
+
/** Flow records or packet samples sent to collectors. */
|
|
83
|
+
flow_export?: FlowExport<NoInfer<I | N>>;
|
|
84
|
+
/** Advertise and learn neighbors with LLDP on every port, or only on the interfaces listed. A port may override it. */
|
|
85
|
+
lldp?: true | { interfaces: readonly NoInfer<I | N>[] };
|
|
86
|
+
/** Spanning tree on every switched port. A port may override it. */
|
|
87
|
+
stp?: {
|
|
88
|
+
/** Which variant runs. RSTP when absent. */
|
|
89
|
+
mode?: "stp" | "rstp" | "mstp";
|
|
90
|
+
/** Bridge priority, 0 to 61440 in steps of 4096. Lower wins the root election. */
|
|
91
|
+
priority?: number;
|
|
92
|
+
};
|
|
93
|
+
/** Forward in hardware where the platform can. An interface may override it. */
|
|
94
|
+
hardware_offload?: boolean;
|
|
95
|
+
};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { Family, IP, Prefix, Rate } from "./common";
|
|
2
|
+
|
|
3
|
+
/** An IP protocol. `icmp` means ICMPv6 in an IPv6 rule. */
|
|
4
|
+
export type Protocol = "tcp" | "udp" | "icmp" | "gre" | "esp" | "ah" | "ospf" | "vrrp";
|
|
5
|
+
|
|
6
|
+
/** The state connection tracking assigns a packet. */
|
|
7
|
+
export type ConnectionState = "new" | "established" | "related" | "untracked" | "invalid";
|
|
8
|
+
|
|
9
|
+
/** A TCP header flag. */
|
|
10
|
+
export type TcpFlag = "fin" | "syn" | "rst" | "psh" | "ack" | "urg";
|
|
11
|
+
|
|
12
|
+
/** Conditions on a packet. All must hold. A rule with addresses of one family applies to that family only. */
|
|
13
|
+
export type FilterMatch<I extends string, AS extends string> = {
|
|
14
|
+
/** Only packets of this family. */
|
|
15
|
+
family?: Family;
|
|
16
|
+
/** IP protocol. */
|
|
17
|
+
protocol?: Protocol;
|
|
18
|
+
/** Source address or prefix. */
|
|
19
|
+
src?: Prefix;
|
|
20
|
+
/** Destination address or prefix. */
|
|
21
|
+
dst?: Prefix;
|
|
22
|
+
/** Source is in this address set. */
|
|
23
|
+
src_set?: AS;
|
|
24
|
+
/** Destination is in this address set. */
|
|
25
|
+
dst_set?: AS;
|
|
26
|
+
/** Source port, or any of several. TCP and UDP only. */
|
|
27
|
+
src_port?: number | readonly number[];
|
|
28
|
+
/** Destination port, or any of several. TCP and UDP only. */
|
|
29
|
+
dst_port?: number | readonly number[];
|
|
30
|
+
/** Arrived on this interface. */
|
|
31
|
+
in_interface?: I;
|
|
32
|
+
/** Leaves through this interface. */
|
|
33
|
+
out_interface?: I;
|
|
34
|
+
/** Connection tracking state, any of these. */
|
|
35
|
+
state?: readonly ConnectionState[];
|
|
36
|
+
/** TCP flags that must be set, and flags that must not be. */
|
|
37
|
+
tcp_flags?: { set?: readonly TcpFlag[]; unset?: readonly TcpFlag[] };
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/** One firewall rule. */
|
|
41
|
+
export type FilterRule<I extends string, AS extends string> = {
|
|
42
|
+
/** Shown beside the rule on the device. */
|
|
43
|
+
description?: string;
|
|
44
|
+
/** Which packets the rule applies to. Every packet when absent. */
|
|
45
|
+
match?: FilterMatch<I, AS>;
|
|
46
|
+
/** What happens to a matching packet. `reject` answers the sender, `drop` does not. */
|
|
47
|
+
action: "accept" | "drop" | "reject";
|
|
48
|
+
/** Hand the rest of an accepted flow to the fast path, past the remaining rules. */
|
|
49
|
+
offload?: true;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** Rules evaluated in order, first match wins, then `default`. */
|
|
53
|
+
export type Chain<I extends string, AS extends string> = {
|
|
54
|
+
/** What happens to a packet no rule matched. Accept when absent. */
|
|
55
|
+
default?: "accept" | "drop";
|
|
56
|
+
/** Evaluated in order. */
|
|
57
|
+
rules?: readonly FilterRule<I, AS>[];
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/** One address translation. */
|
|
61
|
+
export type NatRule<I extends string, AS extends string> = {
|
|
62
|
+
/** Shown beside the rule on the device. */
|
|
63
|
+
description?: string;
|
|
64
|
+
/** Which packets are translated. Every packet when absent. */
|
|
65
|
+
match?: FilterMatch<I, AS>;
|
|
66
|
+
} & (
|
|
67
|
+
| {
|
|
68
|
+
/** Use the address of the outgoing interface. */
|
|
69
|
+
action: "masquerade";
|
|
70
|
+
}
|
|
71
|
+
| {
|
|
72
|
+
/** `snat` rewrites the source, `dnat` the destination. */
|
|
73
|
+
action: "snat" | "dnat";
|
|
74
|
+
/** The address to rewrite to. */
|
|
75
|
+
to: IP;
|
|
76
|
+
/** The port to rewrite to. Unchanged when absent. */
|
|
77
|
+
to_port?: number;
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
/** Connection-tracking helpers that rewrite application payloads. None run unless listed. */
|
|
82
|
+
export type Helper = "ftp" | "tftp" | "sip" | "h323" | "pptp" | "rtsp" | "irc";
|
|
83
|
+
|
|
84
|
+
/** What the device filters and translates. */
|
|
85
|
+
export type Firewall<I extends string, AS extends string> = {
|
|
86
|
+
/** Named groups of addresses and prefixes, of either family, that rules match on. */
|
|
87
|
+
address_sets?: Record<AS, readonly (IP | Prefix)[]>;
|
|
88
|
+
/** Traffic to the device, through it, and from it. */
|
|
89
|
+
filter?: {
|
|
90
|
+
input?: Chain<I, NoInfer<AS>>;
|
|
91
|
+
forward?: Chain<I, NoInfer<AS>>;
|
|
92
|
+
output?: Chain<I, NoInfer<AS>>;
|
|
93
|
+
};
|
|
94
|
+
/** Source translation on the way out, destination translation on the way in. */
|
|
95
|
+
nat?: {
|
|
96
|
+
source?: readonly NatRule<I, NoInfer<AS>>[];
|
|
97
|
+
destination?: readonly NatRule<I, NoInfer<AS>>[];
|
|
98
|
+
};
|
|
99
|
+
/** Helpers that run. None when absent. */
|
|
100
|
+
helpers?: readonly Helper[];
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/** A stateless rule evaluated in hardware where traffic arrives, before routing. */
|
|
104
|
+
export type AclRule<V extends string> = {
|
|
105
|
+
/** Shown beside the rule on the device. */
|
|
106
|
+
description?: string;
|
|
107
|
+
/** Which packets the rule applies to. Every packet when absent. */
|
|
108
|
+
match?: {
|
|
109
|
+
/** Only packets of this family. */
|
|
110
|
+
family?: Family;
|
|
111
|
+
/** IP protocol. */
|
|
112
|
+
protocol?: Protocol;
|
|
113
|
+
/** Source prefix. */
|
|
114
|
+
src?: Prefix;
|
|
115
|
+
/** Destination prefix. */
|
|
116
|
+
dst?: Prefix;
|
|
117
|
+
/** Source port, or any of several. */
|
|
118
|
+
src_port?: number | readonly number[];
|
|
119
|
+
/** Destination port, or any of several. */
|
|
120
|
+
dst_port?: number | readonly number[];
|
|
121
|
+
/** Carried in this VLAN. */
|
|
122
|
+
vlan?: V;
|
|
123
|
+
};
|
|
124
|
+
/** What happens to a matching packet. */
|
|
125
|
+
action: "accept" | "drop";
|
|
126
|
+
/** Accepted traffic above this rate is dropped. */
|
|
127
|
+
rate?: Rate;
|
|
128
|
+
};
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import type { Address, IP, Prefix, Secret } from "./common";
|
|
2
|
+
|
|
3
|
+
/** A VLAN. The key it is declared under is its name. */
|
|
4
|
+
export type Vlan = {
|
|
5
|
+
/** The number carried on the wire, 1 to 4094. */
|
|
6
|
+
id: number;
|
|
7
|
+
/** What the VLAN is for. */
|
|
8
|
+
description?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/** A storm-control threshold: packets per second, or percent of the link's speed. */
|
|
12
|
+
export type Threshold = { pps: number } | { percent: number };
|
|
13
|
+
|
|
14
|
+
/** A virtual router address shared with other devices on the same segment, RFC 5798. */
|
|
15
|
+
export type Vrrp = {
|
|
16
|
+
/** Virtual router number, 1 to 255. The same on every device sharing the address. */
|
|
17
|
+
id: number;
|
|
18
|
+
/** The shared address, without a length. */
|
|
19
|
+
address: IP;
|
|
20
|
+
/** Higher wins the master election, 1 to 254. 100 when absent. */
|
|
21
|
+
priority?: number;
|
|
22
|
+
/** Take mastership back from a lower priority device when this one returns. Off when absent. */
|
|
23
|
+
preempt?: boolean;
|
|
24
|
+
/** Seconds between advertisements. 1 when absent. */
|
|
25
|
+
interval?: number;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** Layer 3 settings shared by every interface that can hold an address. */
|
|
29
|
+
export type Routed<F extends string> = {
|
|
30
|
+
/** Addresses with their length. Use `{ address, peer }` for a point-to-point address whose far end is outside its own prefix. */
|
|
31
|
+
addresses?: readonly (Address | { address: Address; peer: IP })[];
|
|
32
|
+
/** Send IPv6 router advertisements on this interface. Off when absent. */
|
|
33
|
+
ipv6_ra?: boolean;
|
|
34
|
+
/** Overrides the device's `hardware_offload` for traffic routed through this interface. Software forwarding is what makes the firewall apply. */
|
|
35
|
+
hardware_offload?: boolean;
|
|
36
|
+
/** Virtual router addresses held on this interface. */
|
|
37
|
+
vrrp?: readonly Vrrp[];
|
|
38
|
+
/** The VRF this interface routes in. The default table when absent. */
|
|
39
|
+
vrf?: F;
|
|
40
|
+
/** This interface is the network's presence at an internet exchange. Devices ignore it; `circuit peeringdb` publishes it. */
|
|
41
|
+
exchange?: Exchange;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/** Presence at an internet exchange, as a registry lists it. The addresses are the interface's own. */
|
|
45
|
+
export type Exchange = {
|
|
46
|
+
/** The exchange's name, for output. */
|
|
47
|
+
name: string;
|
|
48
|
+
/** Capacity toward the exchange, in Mbit/s. */
|
|
49
|
+
speed: number;
|
|
50
|
+
/** The exchange LAN's id at PeeringDB, its `ixlan_id`. */
|
|
51
|
+
peeringdb_ixlan?: number;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/** Spanning tree settings for one port. */
|
|
55
|
+
export type PortStp = {
|
|
56
|
+
/** The port faces a host, never a switch, so it forwards at once. */
|
|
57
|
+
edge?: boolean;
|
|
58
|
+
/** Path cost. Lower is preferred. Derived from speed when absent. */
|
|
59
|
+
cost?: number;
|
|
60
|
+
/** Port priority, 0 to 240 in steps of 16. Lower is preferred. */
|
|
61
|
+
priority?: number;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Layer 2 membership. A port or LAG with none of these is routed. */
|
|
65
|
+
export type Switched<V extends string> = {
|
|
66
|
+
/** Untagged member of one VLAN. */
|
|
67
|
+
access_vlan?: V;
|
|
68
|
+
/** Tagged member of these VLANs. */
|
|
69
|
+
trunk_vlans?: readonly V[];
|
|
70
|
+
/** Untagged frames on a trunk belong to this VLAN. Only with `trunk_vlans`. */
|
|
71
|
+
native_vlan?: V;
|
|
72
|
+
/** Overrides the device's `stp` for this port. `false` stops it sending or acting on BPDUs. */
|
|
73
|
+
stp?: boolean | PortStp;
|
|
74
|
+
/** Drop flooded traffic above these thresholds. */
|
|
75
|
+
storm_control?: {
|
|
76
|
+
broadcast?: Threshold;
|
|
77
|
+
multicast?: Threshold;
|
|
78
|
+
unknown_unicast?: Threshold;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/** The other end of a cable: another device and its port. Both ends must agree on how they are switched. */
|
|
83
|
+
export type Link = {
|
|
84
|
+
/** Name of the device at the other end. */
|
|
85
|
+
device: string;
|
|
86
|
+
/** The port on that device. */
|
|
87
|
+
port: string;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/** A physical port. Ports a device does not declare are shut down. */
|
|
91
|
+
export type Port<V extends string, A extends string, L extends string, F extends string> = Routed<F> &
|
|
92
|
+
Switched<V> & {
|
|
93
|
+
/** What is plugged in. */
|
|
94
|
+
description?: string;
|
|
95
|
+
/** Largest IP packet, in bytes. 1500 when absent. */
|
|
96
|
+
mtu?: number;
|
|
97
|
+
/** Fixed speed, for an optic slower than the cage. Negotiated when absent. */
|
|
98
|
+
speed?: "100m" | "1g" | "10g" | "25g" | "40g" | "50g" | "100g";
|
|
99
|
+
/** Overrides the device's `lldp` for this port. */
|
|
100
|
+
lldp?: boolean;
|
|
101
|
+
/** Hardware ACL applied to traffic arriving on this port. */
|
|
102
|
+
acl?: A;
|
|
103
|
+
/** Member of this LAG. The LAG holds every other setting. */
|
|
104
|
+
lag?: L;
|
|
105
|
+
/** Another of our devices at the other end of the cable. */
|
|
106
|
+
link?: Link;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/** Settings every interface that is not a physical port shares. */
|
|
110
|
+
type Base<F extends string> = Routed<F> & {
|
|
111
|
+
/** What the interface is for. */
|
|
112
|
+
description?: string;
|
|
113
|
+
/** Largest IP packet, in bytes. */
|
|
114
|
+
mtu?: number;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
/** A layer 3 interface on a VLAN. */
|
|
118
|
+
export type VlanInterface<V extends string, F extends string> = Base<F> & {
|
|
119
|
+
type: "vlan";
|
|
120
|
+
/** The VLAN it sits on. */
|
|
121
|
+
vlan: V;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/** An interface that is always up and belongs to no link, for addresses that must not depend on one. */
|
|
125
|
+
export type Loopback<F extends string> = Base<F> & { type: "loopback" };
|
|
126
|
+
|
|
127
|
+
/** A link aggregation. Member ports name it with `lag`. */
|
|
128
|
+
export type Lag<V extends string, F extends string> = Base<F> &
|
|
129
|
+
Switched<V> & {
|
|
130
|
+
type: "lag";
|
|
131
|
+
/** LACP negotiates membership with the far end; static bundles without asking. LACP when absent. */
|
|
132
|
+
mode?: "lacp" | "static";
|
|
133
|
+
/** Number on platforms that name a LAG by number. Its position among the device's LAGs when absent. */
|
|
134
|
+
id?: number;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/** A GRE tunnel. */
|
|
138
|
+
export type Gre<F extends string> = Base<F> & {
|
|
139
|
+
type: "gre";
|
|
140
|
+
/** Our tunnel endpoint. */
|
|
141
|
+
local: IP;
|
|
142
|
+
/** The far tunnel endpoint. */
|
|
143
|
+
remote: IP;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
/** A point-to-point VXLAN tunnel. */
|
|
147
|
+
export type Vxlan<F extends string> = Base<F> & {
|
|
148
|
+
type: "vxlan";
|
|
149
|
+
/** Segment identifier, the same on both ends. */
|
|
150
|
+
vni: number;
|
|
151
|
+
/** Our tunnel endpoint. */
|
|
152
|
+
local: IP;
|
|
153
|
+
/** The far tunnel endpoint. */
|
|
154
|
+
remote: IP;
|
|
155
|
+
/** UDP port. 4789 when absent. */
|
|
156
|
+
port?: number;
|
|
157
|
+
/** Fixed MAC address, so a rebuild keeps the one the far side learned. */
|
|
158
|
+
mac?: string;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
/** One peer of a WireGuard interface. */
|
|
162
|
+
export type WireGuardPeer = {
|
|
163
|
+
/** Who or what the peer is. */
|
|
164
|
+
name: string;
|
|
165
|
+
/** The peer's public key. Public keys are not secrets. */
|
|
166
|
+
public_key: string;
|
|
167
|
+
/** Addresses the peer may send from and that are routed to it. */
|
|
168
|
+
allowed_addresses: readonly Prefix[];
|
|
169
|
+
/** `host:port`, for a peer this side dials. The peer dials in when absent. */
|
|
170
|
+
endpoint?: string;
|
|
171
|
+
/** Seconds between keepalives, for a peer behind NAT. None when absent. */
|
|
172
|
+
keepalive?: number;
|
|
173
|
+
/** What a generated client config routes into the tunnel. Affects no forwarding here. */
|
|
174
|
+
client_allowed_addresses?: readonly Prefix[];
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/** A WireGuard interface. */
|
|
178
|
+
export type WireGuard<F extends string> = Base<F> & {
|
|
179
|
+
type: "wireguard";
|
|
180
|
+
/** UDP port peers connect to. */
|
|
181
|
+
listen_port: number;
|
|
182
|
+
/** The address clients connect to, for generated client configs. */
|
|
183
|
+
endpoint?: IP;
|
|
184
|
+
/** This interface's private key. Its public key is derived from it. */
|
|
185
|
+
private_key: Secret;
|
|
186
|
+
/** Who may connect. */
|
|
187
|
+
peers?: readonly WireGuardPeer[];
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/** Any interface that is not a physical port. */
|
|
191
|
+
export type Interface<V extends string, F extends string> =
|
|
192
|
+
VlanInterface<V, F> | Loopback<F> | Lag<V, F> | Gre<F> | Vxlan<F> | WireGuard<F>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Family, IP, Prefix } from "./common";
|
|
2
|
+
|
|
3
|
+
/** Registries a prefix set can be fetched from. */
|
|
4
|
+
export type Registry = "ripe-stat";
|
|
5
|
+
|
|
6
|
+
/** Prefixes listed here, or fetched from a registry by `refresh` and never typed by hand. */
|
|
7
|
+
export type PrefixSet =
|
|
8
|
+
| {
|
|
9
|
+
/** The prefixes, of one family. */
|
|
10
|
+
prefixes: readonly Prefix[];
|
|
11
|
+
}
|
|
12
|
+
| {
|
|
13
|
+
source: {
|
|
14
|
+
/** Where the prefixes come from. */
|
|
15
|
+
registry: Registry;
|
|
16
|
+
/** What to ask for, for example `AS7713`. */
|
|
17
|
+
query: string;
|
|
18
|
+
/** Which family to keep. */
|
|
19
|
+
family: Family;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/** Conditions on a route. All must hold. An empty match holds for every route. */
|
|
24
|
+
export type Match<S extends string> = {
|
|
25
|
+
/** Only routes of this family. */
|
|
26
|
+
family?: Family;
|
|
27
|
+
/** Exactly this prefix. */
|
|
28
|
+
prefix?: Prefix;
|
|
29
|
+
/** Any prefix in this set. */
|
|
30
|
+
prefix_set?: S;
|
|
31
|
+
/** Prefix length within this range, inclusive. */
|
|
32
|
+
prefix_length?: { min?: number; max?: number };
|
|
33
|
+
/** AS path length within this range, inclusive. Every AS counts, prepends included. */
|
|
34
|
+
as_path_length?: { min?: number; max?: number };
|
|
35
|
+
/** The route's origin validation state. */
|
|
36
|
+
rpki?: "valid" | "invalid" | "not-found";
|
|
37
|
+
/** Carries this standard community, `asn:value`. */
|
|
38
|
+
community?: string;
|
|
39
|
+
/** Carries this large community, `asn:function:parameter`. */
|
|
40
|
+
large_community?: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** Changes to a route. In community lists to remove, `*` stands for any value of a field, as in `64500:*:*`. */
|
|
44
|
+
export type Sets = {
|
|
45
|
+
/** Preference among routes to the same prefix within our AS. Higher wins. */
|
|
46
|
+
local_pref?: number;
|
|
47
|
+
/** Multi-exit discriminator offered to the neighbor. Lower wins. */
|
|
48
|
+
med?: number;
|
|
49
|
+
/** Prepend our own AS this many times, to make the path look longer. */
|
|
50
|
+
prepend?: number;
|
|
51
|
+
/** Replace the route's standard communities with these. */
|
|
52
|
+
communities?: readonly string[];
|
|
53
|
+
/** Add these standard communities. */
|
|
54
|
+
add_communities?: readonly string[];
|
|
55
|
+
/** Remove standard communities matching these. */
|
|
56
|
+
remove_communities?: readonly string[];
|
|
57
|
+
/** Replace the route's large communities with these. */
|
|
58
|
+
large_communities?: readonly string[];
|
|
59
|
+
/** Add these large communities. */
|
|
60
|
+
add_large_communities?: readonly string[];
|
|
61
|
+
/** Remove large communities matching these. */
|
|
62
|
+
remove_large_communities?: readonly string[];
|
|
63
|
+
/** Next hop for the route. */
|
|
64
|
+
next_hop?: IP;
|
|
65
|
+
/** Source address for traffic the device itself sends to the route. Applies to routes of the same family as the address. */
|
|
66
|
+
preferred_source?: IP;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* One step of a route policy. Evaluated in this order: `call`, then `match`, then `set`, then `action`.
|
|
71
|
+
*
|
|
72
|
+
* A rule without `action` changes the route and moves on to the next rule.
|
|
73
|
+
*/
|
|
74
|
+
export type PolicyRule<P extends string, S extends string> = {
|
|
75
|
+
/** Shown beside the rule on the device. */
|
|
76
|
+
description?: string;
|
|
77
|
+
/** Evaluate another policy first. A route it accepts or rejects stops there. */
|
|
78
|
+
call?: P;
|
|
79
|
+
/** Which routes the rule applies to. Every route when absent. */
|
|
80
|
+
match?: Match<S>;
|
|
81
|
+
/** What to change on a matching route. */
|
|
82
|
+
set?: Sets;
|
|
83
|
+
/** Accept or reject a matching route, ending the policy for it. */
|
|
84
|
+
action?: "accept" | "reject";
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/** Rules evaluated in order, first decision wins. A route no rule accepts is rejected. */
|
|
88
|
+
export type RoutePolicy<P extends string, S extends string> = readonly PolicyRule<P, S>[];
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { Family, IP, Prefix, Secret } from "./common";
|
|
2
|
+
|
|
3
|
+
/** A route the device carries without learning it. */
|
|
4
|
+
export type StaticRoute<I extends string, F extends string> = {
|
|
5
|
+
/** Destination. */
|
|
6
|
+
prefix: Prefix;
|
|
7
|
+
/** Next-hop address. */
|
|
8
|
+
via?: IP;
|
|
9
|
+
/** Next-hop interface, for a link without a next-hop address. */
|
|
10
|
+
interface?: I;
|
|
11
|
+
/** Discard matching traffic. The usual way to originate an aggregate. */
|
|
12
|
+
blackhole?: true;
|
|
13
|
+
/** Preference against other routes to the same prefix. Lower wins. 1 when absent. */
|
|
14
|
+
distance?: number;
|
|
15
|
+
/** The VRF the route belongs to. The default table when absent. */
|
|
16
|
+
vrf?: F;
|
|
17
|
+
/** Why the route exists. */
|
|
18
|
+
description?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Our side of the relationship, as RFC 9234 defines it. */
|
|
22
|
+
export type BgpRole = "provider" | "customer" | "peer" | "rs" | "rs-client";
|
|
23
|
+
|
|
24
|
+
/** Settings a BGP neighbor can state itself or take from its group. */
|
|
25
|
+
export type NeighborSettings<P extends string> = {
|
|
26
|
+
/** The neighbor's AS. Our own AS makes the session internal. */
|
|
27
|
+
remote_as?: number;
|
|
28
|
+
/** Who the neighbor is. */
|
|
29
|
+
description?: string;
|
|
30
|
+
/** Source address for the session. The outgoing interface's address when absent. */
|
|
31
|
+
local_address?: IP;
|
|
32
|
+
/** Policy for routes learned. Nothing is accepted when absent. */
|
|
33
|
+
import?: P;
|
|
34
|
+
/** Policy for routes announced. Nothing is announced when absent. */
|
|
35
|
+
export?: P;
|
|
36
|
+
/** Our role toward this neighbor, which lets both sides reject a leak. */
|
|
37
|
+
local_role?: BgpRole;
|
|
38
|
+
/** The neighbor is more than one hop away. */
|
|
39
|
+
multihop?: boolean;
|
|
40
|
+
/** TCP MD5 password shared with the neighbor. */
|
|
41
|
+
password?: Secret;
|
|
42
|
+
/** Close the session when the neighbor announces more prefixes than this. It stays closed until cleared by hand, on RouterOS with `/routing bgp session clear <session> flag=limit-exceeded`. */
|
|
43
|
+
max_prefixes?: number;
|
|
44
|
+
/** Seconds without a message before the session is declared down. */
|
|
45
|
+
hold_time?: number;
|
|
46
|
+
/** Seconds between keepalive messages. */
|
|
47
|
+
keepalive?: number;
|
|
48
|
+
/** Families exchanged. The family of the neighbor's address when absent. */
|
|
49
|
+
families?: readonly Family[];
|
|
50
|
+
/** Wait for the neighbor to connect instead of connecting to it. */
|
|
51
|
+
passive?: boolean;
|
|
52
|
+
/** Detect a dead link in under a second with BFD. */
|
|
53
|
+
bfd?: boolean;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/** One BGP session. Settings it does not state come from its group. */
|
|
57
|
+
export type Neighbor<P extends string, G extends string> = NeighborSettings<P> & {
|
|
58
|
+
/** The neighbor's address. */
|
|
59
|
+
address: IP;
|
|
60
|
+
/** Group whose settings this neighbor takes where it states none. */
|
|
61
|
+
group?: NoInfer<G>;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** BGP on this device. */
|
|
65
|
+
export type Bgp<P extends string, G extends string> = {
|
|
66
|
+
/** Our AS number. */
|
|
67
|
+
asn: number;
|
|
68
|
+
/** Prefixes this device originates. Each needs a route, for example a static blackhole. Export policy still decides who receives them. */
|
|
69
|
+
networks?: readonly Prefix[];
|
|
70
|
+
/** Settings shared by several neighbors, keyed by group name. */
|
|
71
|
+
groups?: Record<G, NeighborSettings<P>>;
|
|
72
|
+
/** Sessions keyed by name. */
|
|
73
|
+
neighbors?: Record<string, Neighbor<P, G>>;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/** A route origin validation server, RFC 8210. */
|
|
77
|
+
export type RpkiServer = {
|
|
78
|
+
/** Where the validator listens. */
|
|
79
|
+
address: IP;
|
|
80
|
+
/** Its RTR port, often 323 or 8282. */
|
|
81
|
+
port: number;
|
|
82
|
+
/** Who runs it, or why it is here. */
|
|
83
|
+
description?: string;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/** OSPF on one interface. */
|
|
87
|
+
export type OspfInterface = {
|
|
88
|
+
/** Cost of sending through this interface. Lower is preferred. Derived from speed when absent. */
|
|
89
|
+
cost?: number;
|
|
90
|
+
/** Advertise the interface's network but form no adjacency on it. */
|
|
91
|
+
passive?: boolean;
|
|
92
|
+
/** How the link is treated. Broadcast when absent. */
|
|
93
|
+
network?: "broadcast" | "point-to-point";
|
|
94
|
+
/** Detect a dead neighbor in under a second with BFD. */
|
|
95
|
+
bfd?: boolean;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/** OSPF, version 2 for IPv4 and version 3 for IPv6. */
|
|
99
|
+
export type Ospf<I extends string> = {
|
|
100
|
+
/** Which versions run. IPv4 when absent. */
|
|
101
|
+
families?: readonly Family[];
|
|
102
|
+
/** Areas keyed by area ID, for example `0.0.0.0`, each with the interfaces in it. */
|
|
103
|
+
areas: Record<string, { interfaces: Partial<Record<I, OspfInterface>> }>;
|
|
104
|
+
/** Routes from other sources announced into OSPF. */
|
|
105
|
+
redistribute?: readonly ("connected" | "static")[];
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/** Routing on this device. */
|
|
109
|
+
export type Routing<P extends string, G extends string, I extends string, F extends string> = {
|
|
110
|
+
/** Identifies this router to its neighbors. */
|
|
111
|
+
router_id?: IP;
|
|
112
|
+
/** Routes the device carries without learning them. */
|
|
113
|
+
static?: readonly StaticRoute<I, F>[];
|
|
114
|
+
/** BGP sessions and what they exchange. */
|
|
115
|
+
bgp?: Bgp<P, G>;
|
|
116
|
+
/** OSPF areas and interfaces. */
|
|
117
|
+
ospf?: Ospf<I>;
|
|
118
|
+
/** Validators answering route origin validation. */
|
|
119
|
+
rpki?: readonly RpkiServer[];
|
|
120
|
+
};
|