@takodotid/circuit 0.34.0 → 0.34.2
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/dist/cli/index.js +4 -1
- package/dist/presets/index.js +12 -9
- package/dist/types/presets/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/adapters/devices/routeros/TRAPS.md +3 -0
- package/src/adapters/devices/routeros/plan.ts +2 -0
- package/src/adapters/devices/vrp/TRAPS.md +1 -0
- package/src/adapters/devices/vrp/index.ts +4 -0
- package/src/presets/index.ts +17 -11
package/dist/cli/index.js
CHANGED
|
@@ -6139,6 +6139,7 @@ var ORDER = [
|
|
|
6139
6139
|
"/snmp",
|
|
6140
6140
|
"/tool",
|
|
6141
6141
|
"/user",
|
|
6142
|
+
"/system logging action",
|
|
6142
6143
|
"/system"
|
|
6143
6144
|
];
|
|
6144
6145
|
function rank(menu) {
|
|
@@ -7779,7 +7780,8 @@ var DEVICE_FACTS3 = [
|
|
|
7779
7780
|
"authorization-scheme default",
|
|
7780
7781
|
"accounting-scheme default",
|
|
7781
7782
|
"domain default",
|
|
7782
|
-
"Info:"
|
|
7783
|
+
"Info:",
|
|
7784
|
+
"snmp-agent local-engineid"
|
|
7783
7785
|
];
|
|
7784
7786
|
var UNDO_BY_KEYWORD2 = /^(description|name|port default vlan|port link-type|port trunk pvid vlan|set authentication password|eth-trunk|ip binding vpn-instance|ssh server cipher|ssh server hmac|ssh server key-exchange)\b/;
|
|
7785
7787
|
function undo2(line) {
|
|
@@ -8170,6 +8172,7 @@ function snmp4(config, device) {
|
|
|
8170
8172
|
config.line("snmp-agent mib-view included all iso");
|
|
8171
8173
|
config.line(`snmp-agent group v3 ${SNMP_GROUP3} privacy read-view all${guarded ? ` acl ${MANAGEMENT_ACL2}` : ""}`);
|
|
8172
8174
|
for (const [name, user] of Object.entries(snmp.users)) {
|
|
8175
|
+
config.line(`snmp-agent usm-user v3 ${name}`);
|
|
8173
8176
|
config.line(`snmp-agent usm-user v3 ${name} group ${SNMP_GROUP3}`);
|
|
8174
8177
|
config.line(`snmp-agent usm-user v3 ${name} authentication-mode ${SNMP_AUTH4[user.auth]} cipher ${marker(user.auth_password)}`);
|
|
8175
8178
|
config.line(`snmp-agent usm-user v3 ${name} privacy-mode ${SNMP_PRIVACY3[user.privacy]} cipher ${marker(user.privacy_password)}`);
|
package/dist/presets/index.js
CHANGED
|
@@ -33,10 +33,6 @@ var AMPLIFIERS = {
|
|
|
33
33
|
};
|
|
34
34
|
var ASKED = new Set([AMPLIFIERS.dns, AMPLIFIERS.ntp, AMPLIFIERS.snmp]);
|
|
35
35
|
function antiAmplification(destinations, options = {}) {
|
|
36
|
-
const below1024Except = (port) => [
|
|
37
|
-
{ min: 0, max: port - 1 },
|
|
38
|
-
{ min: port + 1, max: 1023 }
|
|
39
|
-
];
|
|
40
36
|
return destinations.flatMap((dst) => [
|
|
41
37
|
...(options.keep_fragments ?? []).filter((prefix) => contains2(dst, prefix)).map((prefix) => ({
|
|
42
38
|
description: `UDP fragments to ${prefix} kept`,
|
|
@@ -44,11 +40,18 @@ function antiAmplification(destinations, options = {}) {
|
|
|
44
40
|
action: "accept"
|
|
45
41
|
})),
|
|
46
42
|
{ description: `UDP fragments to ${dst}`, match: { protocol: "udp", dst, src_port: 0 }, action: "drop" },
|
|
47
|
-
...Object.entries(AMPLIFIERS).
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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" }])
|
|
52
55
|
]);
|
|
53
56
|
}
|
|
54
57
|
var BAD_TCP_FLAGS = [
|
|
@@ -37,7 +37,7 @@ export type AntiAmplificationOptions = {
|
|
|
37
37
|
* Hardware ACL rules dropping reflected UDP floods toward `destinations`, in the switch chip, without limiting anything else.
|
|
38
38
|
*
|
|
39
39
|
* - Replies from an amplifier no host asks across the internet are dropped.
|
|
40
|
-
* - 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.
|
|
40
|
+
* - 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.
|
|
41
41
|
* - The fragments after the first carry no port, and a switch chip reads them as port 0. They are dropped, but toward `keep_fragments`.
|
|
42
42
|
*/
|
|
43
43
|
export declare function antiAmplification(destinations: readonly Prefix[], options?: AntiAmplificationOptions): AclRule<never>[];
|
package/package.json
CHANGED
|
@@ -44,3 +44,6 @@ Behaviour that looks like something else. Each one has been hit on a real device
|
|
|
44
44
|
- On the serial console, the prompt can come twice after a login. The console echoes a long command wrapped at 80 columns, and a `print` that fills the screen stops at `-- [Q quit|D dump|down]`, where `D` prints the rest.
|
|
45
45
|
- Every VLAN interface on the bridge has the bridge's MAC, and the bridge keeps a frame to that MAC on whatever VLAN it arrives. A gateway in front of a transparent firewall then never gets its replies: they come back on the inside VLAN and stop at the bridge. A MACVLAN on the VLAN interface gives the gateway a MAC of its own, and its replies cross the firewall back; proved with a FortiGate 3700D in transparent mode, the session offloaded to its NP6.
|
|
46
46
|
- A second VLAN interface with the same VLAN ID on the same interface is refused, `already have such vlan`, so a VLAN interface is known by its interface and VLAN ID, and a new name is a rename.
|
|
47
|
+
- A switch rule the chip cannot hold is flagged `I`, invalid, and every rule after it is invalid too, with no log line. On a CCR2216 (98DX8525, 7.23) it came at the sixth distinct `dst-port` range, with 66 rules in all, far below the 1,024 MikroTik lists: the amplifier drops toward every VLAN after it did nothing. Few distinct ranges, and check `print count-only where invalid` after an apply.
|
|
48
|
+
- A MACVLAN on a VLAN interface is not routed in the switch chip: its connected route never takes the `H` flag, even with `l3-hw-offloading=yes` on the VLAN under it.
|
|
49
|
+
- A `/system logging` rule naming an action that does not exist yet is refused, `input does not match any value of action`, and `:parse` does not catch it. The action is added first; seen on a CCR2216 on 7.23.5, where the refusal restored the backup.
|
|
@@ -23,3 +23,4 @@ Behaviour that looks like something else. Each one has been hit on a CE6855 runn
|
|
|
23
23
|
- A VLAN name is unique across VLANs: a new VLAN cannot take a name another still has. VLANs no longer used, and their VLAN interfaces, are removed first, in the same candidate.
|
|
24
24
|
- `undo ssh server key-exchange <algorithms>` is refused with "Too many parameters"; `undo ssh server key-exchange` takes none. `hmac` was proved the same way. `cipher` is undone the same way but was not proved on its own.
|
|
25
25
|
- A console on a password only (`passwordOnly`) shows `Please Press ENTER.` after a logout or a refused password, and `Error: The password is invalid.` for a wrong one.
|
|
26
|
+
- Once SNMP is on, the switch prints an engine ID of its own, `snmp-agent local-engineid`, derived from its MAC, and prints each SNMPv3 user as a bare `snmp-agent usm-user v3 <name>` line before its settings. Planning against either as unrendered would undo the user; seen on a CE6855 on V200R005C00SPC800.
|
|
@@ -33,6 +33,8 @@ const DEVICE_FACTS = [
|
|
|
33
33
|
"accounting-scheme default",
|
|
34
34
|
"domain default",
|
|
35
35
|
"Info:",
|
|
36
|
+
// Derived from the switch's MAC once SNMP is on.
|
|
37
|
+
"snmp-agent local-engineid",
|
|
36
38
|
];
|
|
37
39
|
|
|
38
40
|
/** Lines whose removal takes only their keyword, not their value. */
|
|
@@ -493,6 +495,8 @@ function snmp(config: Config, device: Device): void {
|
|
|
493
495
|
config.line(`snmp-agent group v3 ${SNMP_GROUP} privacy read-view all${guarded ? ` acl ${MANAGEMENT_ACL}` : ""}`);
|
|
494
496
|
|
|
495
497
|
for (const [name, user] of Object.entries(snmp.users)) {
|
|
498
|
+
// The switch prints a user's own line before its settings.
|
|
499
|
+
config.line(`snmp-agent usm-user v3 ${name}`);
|
|
496
500
|
config.line(`snmp-agent usm-user v3 ${name} group ${SNMP_GROUP}`);
|
|
497
501
|
config.line(`snmp-agent usm-user v3 ${name} authentication-mode ${SNMP_AUTH[user.auth]} cipher ${marker(user.auth_password)}`);
|
|
498
502
|
config.line(
|
package/src/presets/index.ts
CHANGED
|
@@ -54,15 +54,10 @@ export type AntiAmplificationOptions = {
|
|
|
54
54
|
* Hardware ACL rules dropping reflected UDP floods toward `destinations`, in the switch chip, without limiting anything else.
|
|
55
55
|
*
|
|
56
56
|
* - Replies from an amplifier no host asks across the internet are dropped.
|
|
57
|
-
* - 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.
|
|
57
|
+
* - 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.
|
|
58
58
|
* - The fragments after the first carry no port, and a switch chip reads them as port 0. They are dropped, but toward `keep_fragments`.
|
|
59
59
|
*/
|
|
60
60
|
export function antiAmplification(destinations: readonly Prefix[], options: AntiAmplificationOptions = {}): AclRule<never>[] {
|
|
61
|
-
const below1024Except = (port: number) => [
|
|
62
|
-
{ min: 0, max: port - 1 },
|
|
63
|
-
{ min: port + 1, max: 1023 },
|
|
64
|
-
];
|
|
65
|
-
|
|
66
61
|
return destinations.flatMap((dst) => [
|
|
67
62
|
...(options.keep_fragments ?? [])
|
|
68
63
|
.filter((prefix) => contains(dst, prefix))
|
|
@@ -72,11 +67,22 @@ export function antiAmplification(destinations: readonly Prefix[], options: Anti
|
|
|
72
67
|
action: "accept",
|
|
73
68
|
})),
|
|
74
69
|
{ description: `UDP fragments to ${dst}`, match: { protocol: "udp", dst, src_port: 0 }, action: "drop" },
|
|
75
|
-
...Object.entries(AMPLIFIERS).
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
70
|
+
...Object.entries(AMPLIFIERS).flatMap(([name, port]): AclRule<never>[] =>
|
|
71
|
+
ASKED.has(port)
|
|
72
|
+
? [
|
|
73
|
+
{
|
|
74
|
+
description: `UDP to ${dst} from ${name}, between two servers`,
|
|
75
|
+
match: { protocol: "udp", dst, src_port: port, dst_port: port },
|
|
76
|
+
action: "accept",
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
description: `UDP to ${dst} from ${name}, to a port below 1024`,
|
|
80
|
+
match: { protocol: "udp", dst, src_port: port, dst_port: { min: 0, max: 1023 } },
|
|
81
|
+
action: "drop",
|
|
82
|
+
},
|
|
83
|
+
]
|
|
84
|
+
: [{ description: `UDP to ${dst} from ${name}`, match: { protocol: "udp", dst, src_port: port }, action: "drop" }]
|
|
85
|
+
),
|
|
80
86
|
]);
|
|
81
87
|
}
|
|
82
88
|
|