@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.
Files changed (240) hide show
  1. package/README.md +14 -15
  2. package/dist/chunks/index-20kcjxjg.js +174 -0
  3. package/dist/chunks/index-2r4bbhac.js +977 -0
  4. package/dist/chunks/index-n7w3tg5y.js +149 -0
  5. package/dist/chunks/new-w3zys5y4.js +172 -0
  6. package/dist/chunks/server-gzsf5me5.js +259 -0
  7. package/dist/cli/index.js +11345 -9024
  8. package/dist/helpers/index.js +594 -0
  9. package/dist/index.js +9 -28
  10. package/dist/types/core/{addresses.d.ts → address-space.d.ts} +23 -7
  11. package/dist/types/core/address.d.ts +44 -0
  12. package/dist/types/core/cabling.d.ts +41 -0
  13. package/dist/types/core/cross-checks.d.ts +28 -0
  14. package/dist/types/core/define.d.ts +25 -3
  15. package/dist/types/core/project-files.d.ts +12 -0
  16. package/dist/types/core/schema-docs.d.ts +13 -4
  17. package/dist/types/core/secrets.d.ts +62 -21
  18. package/dist/types/core/{graph.d.ts → topology.d.ts} +32 -12
  19. package/dist/types/core/utils.d.ts +8 -0
  20. package/dist/types/core/validator.d.ts +19 -0
  21. package/dist/types/helpers/bgp.d.ts +97 -0
  22. package/dist/types/helpers/checks.d.ts +32 -0
  23. package/dist/types/helpers/exchange.d.ts +49 -0
  24. package/dist/types/helpers/filters.d.ts +51 -0
  25. package/dist/types/helpers/index.d.ts +10 -0
  26. package/dist/types/helpers/route-server.d.ts +52 -0
  27. package/dist/types/index.d.ts +5 -3
  28. package/dist/types/integrations/librenms.d.ts +60 -0
  29. package/dist/types/integrations/netbox.d.ts +89 -0
  30. package/dist/types/integrations/peeringdb.d.ts +24 -0
  31. package/dist/types/integrations/prometheus.d.ts +24 -0
  32. package/dist/types/integrations/registries.d.ts +8 -0
  33. package/dist/types/platforms/bgp-wait.d.ts +18 -0
  34. package/dist/types/platforms/catalog.d.ts +109 -0
  35. package/dist/types/platforms/derive.d.ts +17 -0
  36. package/dist/types/platforms/fortios/firewall.d.ts +45 -0
  37. package/dist/types/platforms/fortios/index.d.ts +134 -0
  38. package/dist/types/platforms/fortios/names.d.ts +52 -0
  39. package/dist/types/platforms/fortios/plan.d.ts +104 -0
  40. package/dist/types/platforms/fortios/render.d.ts +75 -0
  41. package/dist/types/platforms/fortios/routing.d.ts +56 -0
  42. package/dist/types/platforms/fortios/tree.d.ts +37 -0
  43. package/dist/types/platforms/index.d.ts +13 -0
  44. package/dist/types/platforms/junos/bgp.d.ts +44 -0
  45. package/dist/types/platforms/junos/index.d.ts +114 -0
  46. package/dist/types/platforms/junos/render.d.ts +154 -0
  47. package/dist/types/platforms/line-diff.d.ts +67 -0
  48. package/dist/types/platforms/platform.d.ts +120 -0
  49. package/dist/types/platforms/raisecom-ros/index.d.ts +71 -0
  50. package/dist/types/platforms/raisecom-ros/render.d.ts +41 -0
  51. package/dist/types/platforms/routeros/export.d.ts +59 -0
  52. package/dist/types/platforms/routeros/index.d.ts +96 -0
  53. package/dist/types/{adapters/devices → platforms}/routeros/models.d.ts +4 -0
  54. package/dist/types/platforms/routeros/plan.d.ts +54 -0
  55. package/dist/types/platforms/routeros/render.d.ts +240 -0
  56. package/dist/types/platforms/vrp/index.d.ts +83 -0
  57. package/dist/types/platforms/vrp/render.d.ts +96 -0
  58. package/dist/types/schema/common.d.ts +12 -6
  59. package/dist/types/schema/index.d.ts +1 -0
  60. package/dist/types/schema/interfaces.d.ts +14 -6
  61. package/dist/types/schema/policy.d.ts +18 -10
  62. package/dist/types/schema/routing.d.ts +14 -1
  63. package/dist/types/schema/system.d.ts +16 -6
  64. package/dist/types/schema/time-zones.d.ts +2 -0
  65. package/dist/types/transport/console.d.ts +79 -23
  66. package/dist/types/transport/path-check.d.ts +32 -0
  67. package/dist/types/transport/ssh.d.ts +17 -15
  68. package/package.json +18 -12
  69. package/src/cli/graph-format.ts +91 -0
  70. package/src/cli/index.ts +1074 -484
  71. package/src/cli/new.ts +208 -175
  72. package/src/cli/rename.ts +97 -91
  73. package/src/core/address-space.ts +320 -0
  74. package/src/core/address.ts +202 -0
  75. package/src/core/cabling.ts +154 -0
  76. package/src/core/cross-checks.ts +364 -0
  77. package/src/core/define.ts +26 -3
  78. package/src/core/project-files.ts +35 -0
  79. package/src/core/schema-docs.ts +138 -130
  80. package/src/core/secrets.ts +170 -76
  81. package/src/core/topology.ts +656 -0
  82. package/src/core/utils.ts +37 -0
  83. package/src/core/validator.ts +407 -0
  84. package/src/helpers/bgp.ts +301 -0
  85. package/src/helpers/checks.ts +178 -0
  86. package/src/helpers/exchange.ts +117 -0
  87. package/src/helpers/filters.ts +107 -0
  88. package/src/helpers/index.ts +12 -0
  89. package/src/helpers/route-server.ts +212 -0
  90. package/src/index.ts +6 -3
  91. package/src/integrations/librenms.ts +291 -0
  92. package/src/integrations/netbox.ts +620 -0
  93. package/src/integrations/peeringdb.ts +173 -0
  94. package/src/integrations/prometheus.ts +90 -0
  95. package/src/integrations/registries.ts +25 -0
  96. package/src/platforms/bgp-wait.ts +41 -0
  97. package/src/platforms/catalog.ts +69 -0
  98. package/src/platforms/derive.ts +117 -0
  99. package/src/{adapters/devices → platforms}/fortios/TRAPS.md +6 -0
  100. package/src/platforms/fortios/firewall.ts +377 -0
  101. package/src/platforms/fortios/index.ts +1060 -0
  102. package/src/platforms/fortios/names.ts +130 -0
  103. package/src/platforms/fortios/plan.ts +929 -0
  104. package/src/platforms/fortios/render.ts +779 -0
  105. package/src/platforms/fortios/routing.ts +476 -0
  106. package/src/platforms/fortios/tree.ts +129 -0
  107. package/src/platforms/index.ts +36 -0
  108. package/src/{adapters/devices → platforms}/junos/TRAPS.md +8 -0
  109. package/src/platforms/junos/bgp.ts +293 -0
  110. package/src/platforms/junos/index.ts +1006 -0
  111. package/src/platforms/junos/render.ts +967 -0
  112. package/src/platforms/line-diff.ts +244 -0
  113. package/src/platforms/platform.ts +122 -0
  114. package/src/platforms/raisecom-ros/TRAPS.md +40 -0
  115. package/src/platforms/raisecom-ros/index.ts +731 -0
  116. package/src/platforms/raisecom-ros/render.ts +328 -0
  117. package/src/{adapters/devices → platforms}/routeros/TRAPS.md +16 -2
  118. package/src/platforms/routeros/export.ts +342 -0
  119. package/src/platforms/routeros/index.ts +636 -0
  120. package/src/{adapters/devices → platforms}/routeros/models.ts +2 -0
  121. package/src/platforms/routeros/plan.ts +444 -0
  122. package/src/platforms/routeros/render.ts +1483 -0
  123. package/src/platforms/vrp/TRAPS.md +45 -0
  124. package/src/platforms/vrp/index.ts +652 -0
  125. package/src/platforms/vrp/render.ts +615 -0
  126. package/src/schema/common.ts +15 -6
  127. package/src/schema/index.ts +1 -0
  128. package/src/schema/interfaces.ts +15 -5
  129. package/src/schema/policy.ts +22 -10
  130. package/src/schema/routing.ts +16 -1
  131. package/src/schema/system.ts +16 -6
  132. package/src/schema/time-zones.ts +482 -0
  133. package/src/studio/data.ts +172 -168
  134. package/src/studio/git.ts +95 -90
  135. package/src/studio/public/app.js +161 -150
  136. package/src/studio/public/compare.js +219 -212
  137. package/src/studio/public/diff.js +77 -75
  138. package/src/studio/public/dom.js +118 -108
  139. package/src/studio/public/evaluate.js +584 -545
  140. package/src/studio/public/export.js +120 -118
  141. package/src/studio/public/graph.js +1343 -1266
  142. package/src/studio/public/net.js +115 -109
  143. package/src/studio/public/tables.js +1135 -1083
  144. package/src/studio/public/tools.js +561 -529
  145. package/src/studio/server.ts +202 -196
  146. package/src/transport/console.ts +363 -271
  147. package/src/transport/path-check.ts +91 -0
  148. package/src/transport/ssh.ts +98 -94
  149. package/templates/colocation/checks.ts +11 -6
  150. package/templates/colocation/edge-01.ts +9 -9
  151. package/templates/colocation/routing.ts +2 -2
  152. package/templates/colocation/tenancy.ts +3 -3
  153. package/templates/colocation/tor-01.ts +3 -3
  154. package/templates/edge-router/checks.ts +4 -4
  155. package/templates/edge-router/edge-01.ts +5 -5
  156. package/templates/edge-router/routing.ts +2 -2
  157. package/templates/project/AGENTS.md +5 -1
  158. package/templates/single-site/checks.ts +2 -2
  159. package/dist/chunks/index-47debt16.js +0 -956
  160. package/dist/chunks/index-v8zgr7wm.js +0 -128
  161. package/dist/chunks/new-ny89s7y7.js +0 -166
  162. package/dist/chunks/server-tjbb3rqc.js +0 -251
  163. package/dist/presets/index.js +0 -394
  164. package/dist/types/adapters/devices/catalog.d.ts +0 -86
  165. package/dist/types/adapters/devices/derive.d.ts +0 -7
  166. package/dist/types/adapters/devices/fortios/firewall.d.ts +0 -23
  167. package/dist/types/adapters/devices/fortios/index.d.ts +0 -58
  168. package/dist/types/adapters/devices/fortios/names.d.ts +0 -48
  169. package/dist/types/adapters/devices/fortios/plan.d.ts +0 -28
  170. package/dist/types/adapters/devices/fortios/render.d.ts +0 -38
  171. package/dist/types/adapters/devices/fortios/routing.d.ts +0 -32
  172. package/dist/types/adapters/devices/fortios/tree.d.ts +0 -33
  173. package/dist/types/adapters/devices/index.d.ts +0 -3
  174. package/dist/types/adapters/devices/junos/bgp.d.ts +0 -11
  175. package/dist/types/adapters/devices/junos/index.d.ts +0 -42
  176. package/dist/types/adapters/devices/junos/render.d.ts +0 -52
  177. package/dist/types/adapters/devices/lines.d.ts +0 -56
  178. package/dist/types/adapters/devices/raisecom-ros/index.d.ts +0 -28
  179. package/dist/types/adapters/devices/routeros/export.d.ts +0 -39
  180. package/dist/types/adapters/devices/routeros/index.d.ts +0 -30
  181. package/dist/types/adapters/devices/routeros/plan.d.ts +0 -4
  182. package/dist/types/adapters/devices/routeros/render.d.ts +0 -100
  183. package/dist/types/adapters/devices/types.d.ts +0 -40
  184. package/dist/types/adapters/devices/vrp/index.d.ts +0 -27
  185. package/dist/types/adapters/registries/index.d.ts +0 -3
  186. package/dist/types/adapters/registries/librenms.d.ts +0 -15
  187. package/dist/types/adapters/registries/peeringdb.d.ts +0 -16
  188. package/dist/types/adapters/registries/prometheus.d.ts +0 -16
  189. package/dist/types/core/across.d.ts +0 -4
  190. package/dist/types/core/addr.d.ts +0 -34
  191. package/dist/types/core/files.d.ts +0 -6
  192. package/dist/types/core/merge.d.ts +0 -4
  193. package/dist/types/core/time.d.ts +0 -2
  194. package/dist/types/core/validate.d.ts +0 -2
  195. package/dist/types/presets/index.d.ts +0 -183
  196. package/src/adapters/devices/catalog.ts +0 -41
  197. package/src/adapters/devices/derive.ts +0 -59
  198. package/src/adapters/devices/fortios/firewall.ts +0 -362
  199. package/src/adapters/devices/fortios/index.ts +0 -923
  200. package/src/adapters/devices/fortios/names.ts +0 -115
  201. package/src/adapters/devices/fortios/plan.ts +0 -888
  202. package/src/adapters/devices/fortios/render.ts +0 -768
  203. package/src/adapters/devices/fortios/routing.ts +0 -444
  204. package/src/adapters/devices/fortios/tree.ts +0 -121
  205. package/src/adapters/devices/index.ts +0 -9
  206. package/src/adapters/devices/junos/bgp.ts +0 -269
  207. package/src/adapters/devices/junos/index.ts +0 -862
  208. package/src/adapters/devices/junos/render.ts +0 -872
  209. package/src/adapters/devices/lines.ts +0 -212
  210. package/src/adapters/devices/raisecom-ros/TRAPS.md +0 -26
  211. package/src/adapters/devices/raisecom-ros/index.ts +0 -700
  212. package/src/adapters/devices/routeros/export.ts +0 -321
  213. package/src/adapters/devices/routeros/index.ts +0 -346
  214. package/src/adapters/devices/routeros/plan.ts +0 -398
  215. package/src/adapters/devices/routeros/render.ts +0 -1490
  216. package/src/adapters/devices/types.ts +0 -38
  217. package/src/adapters/devices/vrp/TRAPS.md +0 -26
  218. package/src/adapters/devices/vrp/index.ts +0 -865
  219. package/src/adapters/registries/index.ts +0 -19
  220. package/src/adapters/registries/librenms.ts +0 -92
  221. package/src/adapters/registries/peeringdb.ts +0 -169
  222. package/src/adapters/registries/prometheus.ts +0 -71
  223. package/src/cli/graph.ts +0 -89
  224. package/src/core/across.ts +0 -350
  225. package/src/core/addr.ts +0 -174
  226. package/src/core/addresses.ts +0 -316
  227. package/src/core/files.ts +0 -32
  228. package/src/core/graph.ts +0 -640
  229. package/src/core/merge.ts +0 -19
  230. package/src/core/time.ts +0 -15
  231. package/src/core/validate.ts +0 -348
  232. package/src/presets/index.ts +0 -579
  233. /package/dist/types/{adapters/devices → platforms}/fortios/models.d.ts +0 -0
  234. /package/dist/types/{adapters/devices → platforms}/junos/models.d.ts +0 -0
  235. /package/dist/types/{adapters/devices → platforms}/raisecom-ros/models.d.ts +0 -0
  236. /package/dist/types/{adapters/devices → platforms}/vrp/models.d.ts +0 -0
  237. /package/src/{adapters/devices → platforms}/fortios/models.ts +0 -0
  238. /package/src/{adapters/devices → platforms}/junos/models.ts +0 -0
  239. /package/src/{adapters/devices → platforms}/raisecom-ros/models.ts +0 -0
  240. /package/src/{adapters/devices → platforms}/vrp/models.ts +0 -0
@@ -0,0 +1,44 @@
1
+ import type { Family, IP, IPv4, Prefix } from "../schema";
2
+ /** Address helpers, for checks of your own. */
3
+ export declare class Address {
4
+ /** IPv4 space another network cannot reach: this host, private, shared, loopback, link-local and documentation, after RFC 6890. */
5
+ private static readonly NOT_GLOBAL_V4;
6
+ static family(address: string): Family;
7
+ /** How many bits an address of the family has: 32 or 128. */
8
+ static bits(family: Family): number;
9
+ /** An address as a number, or null when it is not one. */
10
+ static toNumber(address: string): bigint | null;
11
+ /** `10.0.0.1/24` to its parts. Throws when it is not an address with a length. */
12
+ static split(cidr: string): {
13
+ addr: string;
14
+ len: number;
15
+ family: Family;
16
+ };
17
+ static isValid(text: string): boolean;
18
+ static isCidr(text: string): boolean;
19
+ private static mask;
20
+ /** A number back to the address it stands for. */
21
+ static fromNumber(value: bigint, family: Family): IP;
22
+ /** An address, with or without its length, in one spelling: IPv6 as RFC 5952 writes it, so `2001:DB8:0:0::1` and `2001:db8::1` compare equal. Text that is not an address comes back as it is. */
23
+ static canonical(text: string): string;
24
+ /** `10.0.0.1/24` to `10.0.0.0/24`. */
25
+ static prefixOf(cidr: string): Prefix;
26
+ /** Is the address or prefix `inner` inside `outer`? */
27
+ static contains(outer: string, inner: string): boolean;
28
+ /** The first and last address of a prefix, as numbers. */
29
+ static range(cidr: string): {
30
+ first: bigint;
31
+ last: bigint;
32
+ family: Family;
33
+ };
34
+ /** The fewest prefixes that cover every address from `first` to `last` and nothing else. */
35
+ static prefixesBetween(first: bigint, last: bigint, family: Family): Prefix[];
36
+ /** `/25` to `255.255.255.128`. */
37
+ static netmask(length: number): IPv4;
38
+ /** `/24` to `0.0.0.255`, the inverted mask some ACLs take. */
39
+ static wildcard(length: number): IPv4;
40
+ /** The address with its length dropped. */
41
+ static host(cidr: string): IP;
42
+ /** Whether another network can reach the address. IPv6 is global only inside 2000::/3, less documentation space. */
43
+ static isGlobal(address: string): boolean;
44
+ }
@@ -0,0 +1,41 @@
1
+ import type { Device } from "../schema";
2
+ import type { Finding } from "./define";
3
+ /** A device one of our ports sees at the far end of its cable, over LLDP. */
4
+ export type Neighbor = {
5
+ /** Our port, by Circuit's name, such as `10g-1`. */
6
+ port: string;
7
+ /** The system name the far device sends, its hostname. */
8
+ system: string;
9
+ /** The far device's port, as that device spells it, such as `XGigabitEthernet0/0/1`. */
10
+ remote_port: string;
11
+ };
12
+ export declare class Cabling {
13
+ /** The end of a state file that holds a device's LLDP neighbors, beside its config. */
14
+ static readonly SUFFIX = ".lldp.json";
15
+ /** The file a device's neighbors are saved in. */
16
+ static path(stateDirectory: string, device: string): string;
17
+ /** Save what a device sees, sorted, so a file changes only when a neighbor does. */
18
+ static save(stateDirectory: string, device: string, neighbors: readonly Neighbor[]): void;
19
+ /** Forget what a device saw, when its neighbors could not be read this time. */
20
+ static forget(stateDirectory: string, device: string): void;
21
+ /** What a device saw at its last snapshot, or undefined when its neighbors were never read. */
22
+ static load(stateDirectory: string, device: string): Neighbor[] | undefined;
23
+ private static order;
24
+ /** The device runs LLDP somewhere: on every port, on the interfaces it lists, or on a port that turns it on. */
25
+ static runsAnywhere(device: Device): boolean;
26
+ /** The port runs LLDP, by the port's own `lldp`, or else the device's. */
27
+ static runsOn(device: Device, port: string): boolean;
28
+ /**
29
+ * Warnings where LLDP and `link` disagree, from each device's own view: a cable in another port than `link` names, a cable `link` names that LLDP does not see, and another of our devices on a port without `link`.
30
+ *
31
+ * Only ports where both ends run LLDP, by the config, are compared, and only on devices whose neighbors were read. LLDP can be off at the far end, so each is a warning.
32
+ */
33
+ static compare(devices: readonly Device[], neighbors: ReadonlyMap<string, readonly Neighbor[]>): Finding[];
34
+ /** A system name is the device's name, alone or with a domain after it. */
35
+ private static isDevice;
36
+ private static deviceOf;
37
+ /** A port LLDP reports, as the far device spells it, is that device's port by Circuit's name. */
38
+ private static isPort;
39
+ /** Circuit's name for a port LLDP reports, or the report itself when no port of the device is spelled that way. */
40
+ private static portOf;
41
+ }
@@ -0,0 +1,28 @@
1
+ import type { Device } from "../schema";
2
+ import type { Finding } from "./define";
3
+ export declare class CrossChecks {
4
+ /** Every rule across devices. */
5
+ static run(devices: readonly Device[]): Finding[];
6
+ /** The VLAN ids a port or LAG carries, by how it carries them, so two ends can be compared across devices. */
7
+ private static carried;
8
+ /** How a port carries its VLANs, in words: "VLANs 10, 20 tagged and VLAN 30 untagged as native". */
9
+ private static describeCarried;
10
+ /** VLAN names by id, for the VLANs a port or LAG carries. */
11
+ private static vlanNames;
12
+ /** What a port's settings are kept on: the LAG when the port is a member of one, otherwise the port. */
13
+ private static carrierOf;
14
+ /** The plain addresses of one family on an interface, leaving out point-to-point ones. */
15
+ private static plainAddresses;
16
+ /** Why the two ends of a cable cannot reach each other by address, or undefined when they can. */
17
+ private static addressDisagreement;
18
+ /** A link names a device and port that exist, the far end links back, and both ends carry the same VLANs the same way, with the same MTU, speed and addresses. */
19
+ private static checkLinks;
20
+ /** No address is held by two devices in one VRF. Two loopbacks may hold one on purpose, for anycast, so that is a warning. */
21
+ private static checkAddresses;
22
+ /** A BGP session to an address another of our devices holds needs that device's session back, in the AS it expects, from the address it names. */
23
+ private static checkSessions;
24
+ /** On one segment, a VRRP id has one address and an address has one id, on every device. */
25
+ private static checkVrrp;
26
+ /** A GRE or VXLAN tunnel to another of our devices has a tunnel back there, with the endpoints mirrored and, for VXLAN, the same VNI and port. */
27
+ private static checkTunnels;
28
+ }
@@ -1,4 +1,4 @@
1
- import type { ModelName, PlatformName, PortName } from "../adapters/devices/catalog";
1
+ import type { ModelName, PlatformName, PortName } from "../platforms/catalog";
2
2
  import type { Device, Secret } from "../schema";
3
3
  /** A value resolved by name when a device is applied, from the environment or `.env` beside the config, and through 1Password when that value is an `op://` reference. Never the value itself. */
4
4
  export declare const secret: (name: string) => Secret;
@@ -40,18 +40,40 @@ export type Network = {
40
40
  asn?: number;
41
41
  /** The BGP communities the network defines, printed by `circuit communities` for a looking glass or bgp.tools. */
42
42
  communities?: readonly Community[];
43
+ /**
44
+ * The site each device is at, such as a data centre or an office, by name. Devices ignore it.
45
+ *
46
+ * `circuit netbox` puts the device on the NetBox site of that name, and `circuit librenms` puts it in a LibreNMS device group of that name.
47
+ */
48
+ site?: (device: Device) => string;
43
49
  /** Keeps the network's PeeringDB record in step with the config: `circuit peeringdb`. Needs `asn`. */
44
50
  peeringdb?: {
45
51
  /** An API key with write access to the network's record. */
46
52
  api_key: Secret;
47
53
  };
48
- /** Keeps LibreNMS monitoring every device: `circuit librenms`. */
54
+ /** Keeps LibreNMS monitoring every device, under its name, with its SNMP credentials and location, and in a group for its `site`: `circuit librenms`. */
49
55
  librenms?: {
50
56
  /** Where LibreNMS is, such as `https://librenms.example.com`. */
51
57
  url: string;
52
- /** An API token that can add devices. */
58
+ /** An API token that can add and change devices and device groups. */
53
59
  api_token: Secret;
54
60
  };
61
+ /** Keeps NetBox in step with the config: `circuit netbox`. Needs `site`. */
62
+ netbox?: {
63
+ /** Where NetBox is, such as `https://netbox.example.com`. */
64
+ url: string;
65
+ /** An API token that can write. */
66
+ api_token: Secret;
67
+ /** What NetBox needs to know about a device that its config does not say. */
68
+ device: (device: Device) => NetBoxDevice;
69
+ };
70
+ };
71
+ /** What NetBox needs to know about a device that its config does not say. */
72
+ export type NetBoxDevice = {
73
+ /** The device role's name in NetBox, such as `Core switch`. Circuit makes the role when NetBox has none of that name. */
74
+ role: string;
75
+ /** The device type's model name in NetBox, made by the platform's vendor. The device's `model` when absent. */
76
+ device_type?: string;
55
77
  };
56
78
  /** Declare the network, in `circuit.config.ts`. */
57
79
  export declare const defineNetwork: (network: Network) => Network;
@@ -0,0 +1,12 @@
1
+ export declare class ProjectFiles {
2
+ /** Directories that hold no config of the project's own. */
3
+ private static readonly SKIPPED;
4
+ /** The first name written out after a call to defineDevice: the device's own, not that of another device a link, a peer or a tunnel names further on. */
5
+ private static readonly FIRST_NAME;
6
+ /** Every TypeScript file of the project, relative to its root, in name order. */
7
+ static sources(root: string, directory?: string): string[];
8
+ /** Whether a file's text declares the device: it calls defineDevice and gives it the name, written out whole. */
9
+ static declaresDevice(text: string, name: string): boolean;
10
+ /** The project files that declare the device, relative to the root. */
11
+ static deviceFiles(root: string, name: string, sources?: string[]): string[];
12
+ }
@@ -1,5 +1,3 @@
1
- /** The schema files in reading order, with the title each gets. */
2
- export declare const SCHEMA_FILES: readonly [readonly ["device.ts", "Device"], readonly ["interfaces.ts", "Ports and interfaces"], readonly ["routing.ts", "Routing"], readonly ["policy.ts", "Route policies"], readonly ["firewall.ts", "Firewall and ACLs"], readonly ["system.ts", "System and management"], readonly ["common.ts", "Common values"]];
3
1
  export type Field = {
4
2
  path: string;
5
3
  type: string;
@@ -12,5 +10,16 @@ export type TypeDoc = {
12
10
  includes?: string[];
13
11
  fields: Field[];
14
12
  };
15
- /** Every type in each schema file, in the order given. Every file is read first, so a type is known to take parameters wherever it is used. */
16
- export declare function schemaTypes(sources: readonly string[]): TypeDoc[][];
13
+ export declare class SchemaDocs {
14
+ /** The schema files in reading order, with the title each gets. */
15
+ static readonly FILES: readonly [readonly ["device.ts", "Device"], readonly ["interfaces.ts", "Ports and interfaces"], readonly ["routing.ts", "Routing"], readonly ["policy.ts", "Route policies"], readonly ["firewall.ts", "Firewall and ACLs"], readonly ["system.ts", "System and management"], readonly ["common.ts", "Common values"]];
16
+ /** The text of a JSDoc comment, without its markers, as one paragraph. */
17
+ private static commentText;
18
+ /** What a type parameter stands for, where it is not one of the device's names. */
19
+ private static readonly PARAMETER_MEANING;
20
+ /** A type as a reader needs it: "name" for each of the device's names, and no parameter list on the schema's own types. */
21
+ private static withoutGenerics;
22
+ private static parse;
23
+ /** Every type in each schema file, in the order given. Every file is read first, so a type is known to take parameters wherever it is used. */
24
+ static read(sources: readonly string[]): TypeDoc[][];
25
+ }
@@ -1,21 +1,62 @@
1
- import type { Secret } from "../schema";
2
- /** Find `.env` and secret files from this directory, the config file's, instead of the working directory. */
3
- export declare function useRoot(directory: string): void;
4
- export declare const isSecret: (value: unknown) => value is Secret;
5
- /** How a reference is written inside a marker: a variable's name, or `file:` and a path. */
6
- export declare const referenceOf: (secret: Secret) => string;
7
- /** Where a reference's value comes from, such as `.env` or `1Password, through .env`, without reading it. Undefined when it is set nowhere. */
8
- export declare function sourceOf(reference: string): string | undefined;
9
- /** The value behind a reference, as `referenceOf` writes it. */
10
- declare function valueOf(reference: string): string;
11
- /** The value of a secret, or of a variable named directly. */
12
- export declare const resolve: (secret: Secret | string) => string;
13
- /** How a secret appears in rendered config. Replaced with its value only when sent to a device. */
14
- export declare const marker: (secret: Secret) => string;
15
- /** A marker anywhere in a command. Its group is the reference. */
16
- export declare const MARKER: RegExp;
17
- /** Replace every marker in a command with its value. */
18
- export declare const substitute: (text: string) => string;
19
- /** The value behind one marker's reference, for a platform that takes a secret interactively. */
20
- export declare const valueOfReference: typeof valueOf;
21
- export {};
1
+ import type { Network } from "./define";
2
+ import type { Console, Device, IP, Secret } from "../schema";
3
+ /** How a device is logged in to: its management address and SSH port, its connection user and that user's password, and its console. */
4
+ export type DeviceLogin = {
5
+ /** Absent for a device reached only through its console. */
6
+ host?: IP;
7
+ port: number;
8
+ user: string;
9
+ /** The value, not a reference. Never print it. */
10
+ password: string;
11
+ console?: Console;
12
+ };
13
+ export declare class Secrets {
14
+ /** The directory of the config file. `.env` and secret files are found from here. */
15
+ private static root;
16
+ private static envFile;
17
+ private static readonly fromOnePassword;
18
+ /** Every value read in this run, so `scrub` can hide it. */
19
+ private static readonly revealed;
20
+ /** What `scrub` puts where a secret was. */
21
+ static readonly REDACTED = "<redacted>";
22
+ /** A value in `.env` shorter than this is not hidden: `.env` can hold settings that are not secrets, and hiding a short one would garble the text. */
23
+ private static readonly SHORTEST_DOTENV_VALUE;
24
+ /** A marker anywhere in a command. Its group is the reference. */
25
+ static readonly MARKER: RegExp;
26
+ /** Find `.env` and secret files from this directory, the config file's, instead of the working directory. */
27
+ static useRoot(directory: string): void;
28
+ /** `.env` beside the config, read once. Node and Bun read it the same way they load `.env` themselves: a `#` starts a comment unless the value is quoted. */
29
+ private static dotenv;
30
+ /** An unquoted value is cut at a `#`. A `#` after a space is a comment, but one inside the value, as in `abc#def`, would cut a password short and send that to a device, so it stops the run and asks for quotes. */
31
+ private static refuseCutValues;
32
+ /** Read a 1Password reference with the 1Password CLI, `op`, once per run. */
33
+ private static readOnePassword;
34
+ static isSecret(value: unknown): value is Secret;
35
+ /** How a reference is written inside a marker: a variable's name, or `file:` and a path. */
36
+ static referenceOf(secret: Secret): string;
37
+ /** Where a reference's value comes from, such as `.env` or `1Password, through .env`, without reading it. Undefined when it is set nowhere. */
38
+ static sourceOf(reference: string): string | undefined;
39
+ /** The value behind a reference, as `referenceOf` writes it: one marker's reference, for a platform that takes a secret interactively. */
40
+ static valueOf(reference: string): string;
41
+ /** The value of a secret, or of a variable named directly: from the environment, `.env`, 1Password or a file. */
42
+ static reveal(secret: Secret | string): string;
43
+ /** Every secret reference in a value, however deep, such as a network or one device, as `referenceOf` writes it. */
44
+ static referencesIn(value: unknown, found?: Set<string>): Set<string>;
45
+ /**
46
+ * Text with every secret value Circuit knows replaced by `<redacted>`, before it is printed. Devices echo what they are sent, passwords too.
47
+ *
48
+ * Hidden are: each value in `.env` of at least six characters, each value read in this run (1Password reads and secret files among them), each secret of `network` that the environment, `.env` or a file holds, and `extra`. A 1Password reference not read in this run is not read for this.
49
+ */
50
+ static scrub(text: string, options?: {
51
+ network?: Network;
52
+ extra?: readonly string[];
53
+ }): string;
54
+ /** The value behind a reference when it can be had without asking anyone: a 1Password reference only once read in this run. Undefined otherwise. */
55
+ private static storedValueOf;
56
+ /** How Circuit logs in to a device: its address, port, connection user, that user's password revealed, and its console. */
57
+ static loginOf(device: Device): DeviceLogin;
58
+ /** How a secret appears in rendered config. Replaced with its value only when sent to a device. */
59
+ static marker(secret: Secret): string;
60
+ /** Replace every marker in a command with its value. */
61
+ static substitute(text: string): string;
62
+ }
@@ -2,7 +2,6 @@ import type { Device, Routed } from "../schema";
2
2
  import type { Finding } from "./define";
3
3
  /** One view of the network. Every edge belongs to one. */
4
4
  export type Layer = "l1" | "l2" | "l3" | "bgp" | "ospf" | "tunnels";
5
- export declare const LAYERS: readonly Layer[];
6
5
  /** One of our devices, a segment several of them share, or something outside the network. */
7
6
  export type GraphNode = {
8
7
  /** Unique among the nodes, such as `device:edge-01` or `as:64501`. */
@@ -63,14 +62,35 @@ export type Holder = {
63
62
  /** The VRF the address is in. The default table when absent. */
64
63
  vrf?: string;
65
64
  };
66
- export declare const deviceId: (name: string) => string;
67
- /** An address as a key, so two spellings of one address compare equal. Undefined when it is not an address. */
68
- export declare function keyOf(address: string | undefined): string | undefined;
69
- /** Ports, then interfaces, that can hold an address. */
70
- export declare function routedOf(device: Device): [string, Routed<string>][];
71
- /** Every valid address the devices hold. An invalid one is left for `validate` to report. */
72
- export declare function holdersOf(devices: readonly Device[]): Holder[];
73
- /** The network as a graph. It reads the config only, never a device, and works on a config that does not validate. */
74
- export declare function graphOf(devices: readonly Device[]): Graph;
75
- /** Only the edges on these layers, and among those only the ones that touch these devices when any are named. Every device named stays. */
76
- export declare function only(graph: Graph, layers: readonly Layer[], deviceNames?: readonly string[]): Graph;
65
+ export declare class Topology {
66
+ static readonly LAYERS: readonly Layer[];
67
+ static deviceId(name: string): string;
68
+ /** An address as a key, so two spellings of one address compare equal. Undefined when it is not an address. */
69
+ static keyOf(address: string | undefined): string | undefined;
70
+ private static isHostRoute;
71
+ /** Ports, then interfaces, that can hold an address. */
72
+ static routedOf(device: Device): [string, Routed<string>][];
73
+ /** Every valid address the devices hold. An invalid one is left for `validate` to report. */
74
+ static holders(devices: readonly Device[]): Holder[];
75
+ private static describeDevice;
76
+ /** The VLANs a port or LAG carries, by id. */
77
+ private static carriedBy;
78
+ private static vlanLabel;
79
+ /** `l1`, every cable, with a LAG's member cables as one edge; and `l2`, the VLANs each one carries. */
80
+ private static cables;
81
+ /** `l3`: prefixes several devices hold an address in, and point-to-point addresses whose far end is another device. */
82
+ private static segments;
83
+ /** `bgp`: sessions between our devices, matched by the address each names, and to every AS outside. */
84
+ private static sessions;
85
+ /** `ospf`: two devices with OSPF on interfaces in one area and one prefix, neither passive. */
86
+ private static adjacencies;
87
+ /** `host:port` or `[host]:port` to the host. */
88
+ private static endpointHost;
89
+ /** `tunnels`: GRE and VXLAN tunnels matched by their endpoints, and WireGuard peers matched to the device at the far end. */
90
+ private static tunnels;
91
+ private static wireguard;
92
+ /** The network as a graph. It reads the config only, never a device, and works on a config that does not validate. */
93
+ static of(devices: readonly Device[]): Graph;
94
+ /** Only the edges on these layers, and among those only the ones that touch these devices when any are named. Every device named stays. */
95
+ static only(graph: Graph, layers: readonly Layer[], deviceNames?: readonly string[]): Graph;
96
+ }
@@ -0,0 +1,8 @@
1
+ type Merged<T extends readonly object[]> = T extends readonly [infer Head, ...infer Tail extends readonly object[]] ? Head & Merged<Tail> : unknown;
2
+ export declare class Utils {
3
+ /** Combine records into one, such as a device's own interfaces and those a module derives for it. Unlike spreading them, a name two of them hold is an error rather than one silently replacing the other. */
4
+ static merge<const T extends readonly Record<string, unknown>[]>(...records: T): Merged<T>;
5
+ /** Minutes east of UTC an IANA zone is at now, for platforms that take an offset rather than a zone. */
6
+ static timeZoneOffset(zone: string): number;
7
+ }
8
+ export {};
@@ -0,0 +1,19 @@
1
+ import type { Finding, Network } from "./define";
2
+ export declare class Validator {
3
+ static run(network: Network): Finding[];
4
+ private static checkDevice;
5
+ /** What the model's hardware holds, from the catalog. A LAG with too many members is an error; too many switch rules is a warning, since the limit is only roughly known. */
6
+ private static checkLimits;
7
+ private static checkVlans;
8
+ /** Every address is valid, and no address sits on two interfaces of one routing table. Two VRFs may hold the same address. */
9
+ private static checkAddresses;
10
+ private static checkPorts;
11
+ /** A MAC limit is a whole number above 0, and an ethertype filter lets at least one kind in, each once. */
12
+ private static checkFrames;
13
+ private static checkInterfaces;
14
+ private static checkRouting;
15
+ private static checkPolicies;
16
+ private static checkFirewall;
17
+ private static checkServices;
18
+ private static checkCertificates;
19
+ }
@@ -0,0 +1,97 @@
1
+ import type { Community } from "../core/define";
2
+ import type { Device, PolicyRule, Prefix, StandardCommunity } from "../schema";
3
+ /** The prefix lengths a BGP import accepts. */
4
+ export type SanityLengths = {
5
+ /** Shortest and longest IPv4 prefix accepted. /8 to /24 when absent. */
6
+ ipv4?: {
7
+ min: number;
8
+ max: number;
9
+ };
10
+ /** Shortest and longest IPv6 prefix accepted. /16 to /48 when absent. */
11
+ ipv6?: {
12
+ min: number;
13
+ max: number;
14
+ };
15
+ };
16
+ /** Kinds of neighbor and the number each is tagged with, such as `{ transit: 1, customer: 3 }`. */
17
+ export type CommunityClasses = Readonly<Record<string, number>>;
18
+ /**
19
+ * A BGP community scheme of large communities, `asn:function:parameter`, in the style of RFC 8195. Each field names the function number your network uses for it; leave out what your network does not offer.
20
+ *
21
+ * The type parameters keep the exact numbers you write, so the communities `Bgp.communityScheme` gives back show them in the editor: Asn your AS, LearnedFrom the function of `learned_from`, Classes its classes.
22
+ */
23
+ export type CommunityScheme<Asn extends number = number, LearnedFrom extends number = number, Classes extends CommunityClasses = CommunityClasses> = {
24
+ /** Your AS. It is the first part of every community. */
25
+ asn: Asn;
26
+ /** Set on import: the kind of neighbor a route came from, `asn:function:class`. */
27
+ learned_from?: {
28
+ function: LearnedFrom;
29
+ classes: Classes;
30
+ };
31
+ /** Set on import: the site a route was learned at, `asn:function:site`. `sites` names the sites, for the catalogue. */
32
+ learned_at?: {
33
+ function: number;
34
+ sites?: Readonly<Record<number, string>>;
35
+ };
36
+ /** Set on import: the AS a route was learned from, `asn:function:asn`. */
37
+ learned_from_as?: number;
38
+ /** A neighbor asks: do not announce the route to an AS, `asn:function:asn`, or to anyone, `asn:function:0`. */
39
+ do_not_announce?: number;
40
+ /** A neighbor asks: prepend toward an AS once, twice or three times, `asn:function:asn`. */
41
+ prepend?: {
42
+ once?: number;
43
+ twice?: number;
44
+ three_times?: number;
45
+ };
46
+ /**
47
+ * A neighbor asks: drop all traffic to this route, `asn:function:0`, usually one address under attack. Your router drops it, and so does every upstream in `upstreams`.
48
+ *
49
+ * `upstreams` maps an upstream's AS to its own blackhole community, as its NOC gives it. The route is passed to that upstream with it, so the traffic stops before it reaches your links. An upstream not listed never receives the route.
50
+ */
51
+ blackhole?: {
52
+ function: number;
53
+ upstreams?: Readonly<Record<number, StandardCommunity>>;
54
+ };
55
+ };
56
+ /** The class names a scheme declares, or any name when it declares none. */
57
+ type ClassName<Classes extends CommunityClasses> = {} extends Classes ? string : Extract<keyof Classes, string>;
58
+ /** BGP policy: an import sanity policy, a community scheme, and helpers that read a device's BGP neighbors. */
59
+ export declare class Bgp {
60
+ private static readonly PREPENDS;
61
+ /** Route policy rules rejecting what no neighbor should send: prefixes too short or too long for the global table, and RPKI invalid. Place it first in an import, or as a policy other imports call. */
62
+ static sanity(lengths?: SanityLengths): PolicyRule<never, never>[];
63
+ /** Each BGP neighbor's own policies and role, or its group's. */
64
+ static neighborPolicies(device: Device): {
65
+ name: string;
66
+ address: import("..").IP;
67
+ role: import("..").BgpRole | undefined;
68
+ import: string | undefined;
69
+ export: string | undefined;
70
+ }[];
71
+ /** The prefixes an export policy accepts by name. */
72
+ static offered(device: Device, policy: string | undefined): Prefix[];
73
+ /**
74
+ * Policy rules and a catalogue from one community scheme, so the communities your routers set, the ones they act on, and the ones you publish never disagree.
75
+ *
76
+ * - `tag(neighborClass, neighborAs, { site, trusted })`: a rule for an import policy. It removes your communities a neighbor set, then adds where the route was learned. A `trusted` neighbor keeps its requests: do not announce, prepend, blackhole. `site` is needed when the scheme has `learned_at`.
77
+ * - `actions(neighborAs, { blackhole })`: rules for an export policy toward one neighbor. They act on a customer's action communities, then remove all of yours. Place them before the rules that accept. A blackholed route goes no further, unless `blackhole` names the neighbor's own blackhole community: then it is passed on with it, so the neighbor drops the traffic too.
78
+ * - `blackhole(prefixSets)`: rules for the import policy of a neighbor you trust with blackholes, before anything that rejects long prefixes. They take a route the neighbor asked to blackhole, but only inside `prefixSets`, its own space, and drop traffic to it here. One rule per set, so one call covers both families.
79
+ * - `catalogue`: every community, for `communities` in `defineNetwork`.
80
+ * - `community(fn, parameter)`: one community of yours, for a rule of your own.
81
+ * - `learned_from`: the community each class is tagged with, by class name, such as `learned_from.customer`.
82
+ */
83
+ static communityScheme<const Asn extends number, const LearnedFrom extends number = number, const Classes extends CommunityClasses = {}>(scheme: CommunityScheme<Asn, LearnedFrom, Classes>): {
84
+ community: <const Fn extends number, const Parameter extends number>(fn: Fn, parameter: Parameter) => `${Asn}:${Fn}:${Parameter}`;
85
+ learned_from: { readonly [Name in keyof Classes]: `${Asn}:${LearnedFrom}:${Classes[Name]}`; };
86
+ tag: (neighborClass: ClassName<Classes>, neighborAs: number, options?: {
87
+ site?: number;
88
+ trusted?: boolean;
89
+ }) => PolicyRule<never, never>;
90
+ actions: (neighborAs: number) => PolicyRule<never, never>[];
91
+ blackhole: <S extends string>(prefixSets: readonly S[]) => PolicyRule<never, S>[];
92
+ catalogue: Community[];
93
+ };
94
+ /** A word with its article: "a customer", "an upstream". */
95
+ private static article;
96
+ }
97
+ export {};
@@ -0,0 +1,32 @@
1
+ import type { Check } from "../core/define";
2
+ /** Where traffic from outside, before anything filters it, may go. Every VLAN not listed as untrusted is trusted, so a VLAN added later is protected without being listed. */
3
+ export type TrustBoundary = {
4
+ /** VLANs carrying traffic straight from outside: transits, exchanges, an ISP handoff. */
5
+ untrusted: readonly string[];
6
+ /** The devices that filter: the only ones that may give an untrusted VLAN an address, and the only ones a port carrying both kinds may face. */
7
+ routers: readonly string[];
8
+ /**
9
+ * Links between two switches that may carry both kinds, each named by its two devices: a site's switch extended to another building, with an exchange's VLAN and its own management on one cable. Neither end gives an untrusted VLAN an address.
10
+ */
11
+ extended?: readonly (readonly [string, string])[];
12
+ };
13
+ /** Checks for `checks` in `defineNetwork`, and helpers for checks of your own. */
14
+ export declare class Checks {
15
+ /**
16
+ * Every BGP export ends in a reject that matches everything, so nothing leaves by accident. An export to a neighbor whose `role` is `customer` is left out: sending a customer everything you know is what it pays for, and cannot leak a route to the rest of the internet.
17
+ */
18
+ static readonly exportsEndInReject: Check;
19
+ /** A GRE or VXLAN tunnel's local address is outside what the neighbors over it are offered, or their replies route back into the tunnel. */
20
+ static readonly tunnelsOutsideOffered: Check;
21
+ /**
22
+ * A native VLAN is a dead end: native on one trunk (a port or a LAG) of a device at most, and never an access VLAN or a tagged VLAN anywhere on that device. On a switch, a native VLAN is an untagged member of every trunk it is native on, so one native VLAN shared by two trunks joins them: every untagged frame from one leaves on the other.
23
+ */
24
+ static readonly nativeVlansAreDeadEnds: Check;
25
+ /** The VLANs a port carries, untagged or tagged. */
26
+ static vlansOf(port: {
27
+ access_vlan?: string;
28
+ trunk_vlans?: readonly string[];
29
+ }): string[];
30
+ /** A check: traffic from outside reaches your own VLANs only through a router. A port or LAG carrying an untrusted VLAN beside any other is on a router or faces one, and only a router gives an untrusted VLAN an address. */
31
+ static trustBoundary(boundary: TrustBoundary): Check;
32
+ }
@@ -0,0 +1,49 @@
1
+ import type { Check } from "../core/define";
2
+ import type { Ethertype, IP, Port, Prefix } from "../schema";
3
+ import { type RouteServer } from "./route-server";
4
+ /** A member of an internet exchange: a network with a port on the fabric and an address on the peering LAN. */
5
+ export type ExchangeMember = {
6
+ /** Lowercase, and never reused. */
7
+ name: string;
8
+ asn: number;
9
+ /** The member's port on each fabric switch, by switch name. */
10
+ ports: Readonly<Record<string, string>>;
11
+ /** Its addresses on the peering LAN. The route servers peer with these. */
12
+ ipv4?: IP;
13
+ ipv6?: IP;
14
+ };
15
+ /** An internet exchange's peering LAN, as its fabric carries it. */
16
+ export type InternetExchange<V extends string> = {
17
+ /** The peering VLAN, by the name the fabric switches give it. */
18
+ vlan: V;
19
+ /** The peering LAN's subnets. */
20
+ lan: {
21
+ ipv4?: Prefix;
22
+ ipv6?: Prefix;
23
+ };
24
+ /** Addresses on the peering LAN no member may take, such as the route servers'. */
25
+ reserved?: readonly IP[];
26
+ /** How much broadcast, multicast and unknown unicast a member port lets through, in percent of its speed. 1 when absent. */
27
+ storm_percent?: number;
28
+ /** The most MAC addresses a member port learns, usually 1. No limit when absent. No platform renders it yet, so `validate` refuses it. */
29
+ mac_limit?: number;
30
+ /** The only kinds of frame a member port takes in, usually `ipv4`, `ipv6` and `arp`. Every kind when absent. No platform renders it yet, so `validate` refuses it. */
31
+ ethertypes?: readonly Ethertype[];
32
+ };
33
+ /** An internet exchange's fabric: its member ports, a check of its members, and its route servers' config. */
34
+ export declare class Exchange {
35
+ /**
36
+ * Member ports and a check for an internet exchange's fabric.
37
+ *
38
+ * - `ports(device)`: every member's port on one switch. A member port is in the peering VLAN and nothing else, takes no part in spanning tree or LLDP, and lets only a trickle of broadcast, multicast and unknown unicast through. With `mac_limit` and `ethertypes`, it also learns that many MAC addresses at most and takes in only those kinds of frame.
39
+ * - `check`: members never share a name, an AS, an address or a port; every address is inside the peering LAN and not reserved; every member port carries the peering VLAN alone.
40
+ * - `bird(server)`: one route server's BIRD 2 config, with a session to every member. Write it to a file for the server; Circuit never logs in to a route server.
41
+ * - `openbgpd(server)`: the same route server's config for OpenBGPD, its `bgpd.conf`, with the same sessions and the same rules.
42
+ */
43
+ static build<const V extends string>(exchange: InternetExchange<V>, members: readonly ExchangeMember[]): {
44
+ ports: (device: string) => Record<string, Port<V, string, string, string>>;
45
+ check: Check;
46
+ bird: (server: RouteServer) => string;
47
+ openbgpd: (server: RouteServer) => string;
48
+ };
49
+ }
@@ -0,0 +1,51 @@
1
+ import type { AclRule, FilterRule, Prefix } from "../schema";
2
+ /** What `Filters.antiAmplification` leaves alone. */
3
+ export type AntiAmplificationOptions = {
4
+ /** Prefixes inside the destinations whose UDP fragments pass: for a host that receives UDP too large for one packet, such as SIP or some VPNs. Every fragment after the first is dropped when absent. */
5
+ keep_fragments?: readonly Prefix[];
6
+ };
7
+ /** Address lists and edge filters: hardware ACL rules and firewall rules for traffic from outside. */
8
+ export declare class Filters {
9
+ /** IPv4 sources that never arrive from the internet: loopback, link-local and "this network", after RFC 6890. */
10
+ static readonly MARTIANS: readonly ["127.0.0.0/8", "169.254.0.0/16", "0.0.0.0/8"];
11
+ /** IPv4 private space, RFC 1918. */
12
+ static readonly PRIVATE_RANGES: readonly ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"];
13
+ /** UDP ports of services that answer a small request with a much larger reply, which attackers use to reflect floods at a victim. A reflected flood arrives from these ports. */
14
+ static readonly AMPLIFIERS: {
15
+ readonly qotd: 17;
16
+ readonly chargen: 19;
17
+ readonly dns: 53;
18
+ readonly portmap: 111;
19
+ readonly ntp: 123;
20
+ readonly netbios: 137;
21
+ readonly snmp: 161;
22
+ readonly cldap: 389;
23
+ readonly slp: 427;
24
+ readonly rip: 520;
25
+ readonly "ms-sql": 1434;
26
+ readonly ssdp: 1900;
27
+ readonly ard: 3283;
28
+ readonly "ws-discovery": 3702;
29
+ readonly mdns: 5353;
30
+ readonly coap: 5683;
31
+ readonly ubiquiti: 10001;
32
+ readonly memcached: 11211;
33
+ readonly dvr: 37810;
34
+ };
35
+ /** Of the amplifiers, the services hosts do ask across the internet: resolvers, time servers, monitoring. A reply to a real request goes back to the asking port, 1024 or above, or to the service's own port when two servers talk. */
36
+ private static readonly ASKED;
37
+ /** TCP flag combinations no legitimate packet carries: name, flags set, flags unset. */
38
+ private static readonly BAD_TCP_FLAGS;
39
+ /** Hardware ACL rules dropping traffic arriving on a VLAN from sources that cannot be there: your own space, martians, private ranges. One rule per source. */
40
+ static antiSpoofing<V extends string>(vlan: V, sources: readonly Prefix[]): AclRule<V>[];
41
+ /**
42
+ * Hardware ACL rules dropping reflected UDP floods toward `destinations`, in the switch chip, without limiting anything else.
43
+ *
44
+ * - Replies from an amplifier no host asks across the internet are dropped.
45
+ * - Replies from DNS, NTP and SNMP are dropped only toward a port below 1024 that is not the service's own. A host that runs its own resolver, time server or monitoring keeps its answers. The service's own port passes first, so every drop takes the one range 0 to 1023: a switch chip has few port-range checkers, and on RouterOS a rule past them is invalid with every rule after it.
46
+ * - The fragments after the first carry no port, and a switch chip reads them as port 0. They are dropped, but toward `keep_fragments`.
47
+ */
48
+ static antiAmplification(destinations: readonly Prefix[], options?: AntiAmplificationOptions): AclRule<never>[];
49
+ /** Firewall rules dropping packets with a TCP flag combination no legitimate packet carries, for a forward chain. */
50
+ static badTcpFlags(): FilterRule<never, never>[];
51
+ }
@@ -0,0 +1,10 @@
1
+ export { Bgp } from "./bgp";
2
+ export type { CommunityScheme, SanityLengths } from "./bgp";
3
+ export { Checks } from "./checks";
4
+ export type { TrustBoundary } from "./checks";
5
+ export { Exchange } from "./exchange";
6
+ export type { ExchangeMember, InternetExchange } from "./exchange";
7
+ export { Filters } from "./filters";
8
+ export { RouteServerConfig } from "./route-server";
9
+ export type { RouteServer } from "./route-server";
10
+ export type { AntiAmplificationOptions } from "./filters";