@sentriflow/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +190 -0
- package/README.md +86 -0
- package/package.json +60 -0
- package/src/constants.ts +77 -0
- package/src/engine/RuleExecutor.ts +256 -0
- package/src/engine/Runner.ts +312 -0
- package/src/engine/SandboxedExecutor.ts +208 -0
- package/src/errors.ts +88 -0
- package/src/helpers/arista/helpers.ts +1220 -0
- package/src/helpers/arista/index.ts +12 -0
- package/src/helpers/aruba/helpers.ts +637 -0
- package/src/helpers/aruba/index.ts +13 -0
- package/src/helpers/cisco/helpers.ts +534 -0
- package/src/helpers/cisco/index.ts +11 -0
- package/src/helpers/common/helpers.ts +265 -0
- package/src/helpers/common/index.ts +5 -0
- package/src/helpers/common/validation.ts +280 -0
- package/src/helpers/cumulus/helpers.ts +676 -0
- package/src/helpers/cumulus/index.ts +12 -0
- package/src/helpers/extreme/helpers.ts +422 -0
- package/src/helpers/extreme/index.ts +12 -0
- package/src/helpers/fortinet/helpers.ts +892 -0
- package/src/helpers/fortinet/index.ts +12 -0
- package/src/helpers/huawei/helpers.ts +790 -0
- package/src/helpers/huawei/index.ts +11 -0
- package/src/helpers/index.ts +53 -0
- package/src/helpers/juniper/helpers.ts +756 -0
- package/src/helpers/juniper/index.ts +12 -0
- package/src/helpers/mikrotik/helpers.ts +722 -0
- package/src/helpers/mikrotik/index.ts +12 -0
- package/src/helpers/nokia/helpers.ts +856 -0
- package/src/helpers/nokia/index.ts +11 -0
- package/src/helpers/paloalto/helpers.ts +939 -0
- package/src/helpers/paloalto/index.ts +12 -0
- package/src/helpers/vyos/helpers.ts +429 -0
- package/src/helpers/vyos/index.ts +12 -0
- package/src/index.ts +30 -0
- package/src/json-rules/ExpressionEvaluator.ts +292 -0
- package/src/json-rules/HelperRegistry.ts +177 -0
- package/src/json-rules/JsonRuleCompiler.ts +339 -0
- package/src/json-rules/JsonRuleValidator.ts +371 -0
- package/src/json-rules/index.ts +97 -0
- package/src/json-rules/schema.json +350 -0
- package/src/json-rules/types.ts +303 -0
- package/src/pack-loader/PackLoader.ts +332 -0
- package/src/pack-loader/index.ts +17 -0
- package/src/pack-loader/types.ts +135 -0
- package/src/parser/IncrementalParser.ts +527 -0
- package/src/parser/Sanitizer.ts +104 -0
- package/src/parser/SchemaAwareParser.ts +504 -0
- package/src/parser/VendorSchema.ts +72 -0
- package/src/parser/vendors/arista-eos.ts +206 -0
- package/src/parser/vendors/aruba-aoscx.ts +123 -0
- package/src/parser/vendors/aruba-aosswitch.ts +113 -0
- package/src/parser/vendors/aruba-wlc.ts +173 -0
- package/src/parser/vendors/cisco-ios.ts +110 -0
- package/src/parser/vendors/cisco-nxos.ts +107 -0
- package/src/parser/vendors/cumulus-linux.ts +161 -0
- package/src/parser/vendors/extreme-exos.ts +154 -0
- package/src/parser/vendors/extreme-voss.ts +167 -0
- package/src/parser/vendors/fortinet-fortigate.ts +217 -0
- package/src/parser/vendors/huawei-vrp.ts +192 -0
- package/src/parser/vendors/index.ts +1521 -0
- package/src/parser/vendors/juniper-junos.ts +230 -0
- package/src/parser/vendors/mikrotik-routeros.ts +274 -0
- package/src/parser/vendors/nokia-sros.ts +251 -0
- package/src/parser/vendors/paloalto-panos.ts +264 -0
- package/src/parser/vendors/vyos-vyos.ts +454 -0
- package/src/types/ConfigNode.ts +72 -0
- package/src/types/DeclarativeRule.ts +158 -0
- package/src/types/IRule.ts +270 -0
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
// packages/rule-helpers/src/mikrotik/helpers.ts
|
|
2
|
+
// MikroTik RouterOS-specific helper functions
|
|
3
|
+
|
|
4
|
+
import type { ConfigNode } from '../../types/ConfigNode';
|
|
5
|
+
import { parseIp, prefixToMask } from '../common/helpers';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Check if a MikroTik resource is disabled (has disabled=yes property)
|
|
9
|
+
*/
|
|
10
|
+
export const isDisabledResource = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
11
|
+
const id = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
12
|
+
const lower = id.toLowerCase();
|
|
13
|
+
return (
|
|
14
|
+
/\bdisabled=yes\b/i.test(lower) ||
|
|
15
|
+
/\bdisabled="?yes"?\b/i.test(lower)
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Check if interface is a physical ethernet port (ether1, ether2, etc.)
|
|
21
|
+
*/
|
|
22
|
+
export const isPhysicalInterface = (interfaceName: string): boolean => {
|
|
23
|
+
const name = interfaceName.toLowerCase();
|
|
24
|
+
// MikroTik physical ethernet interfaces: ether1, ether2, etc.
|
|
25
|
+
// Also match sfp1, sfp-sfpplus1, combo1, etc.
|
|
26
|
+
return /^ether\d+$/.test(name) ||
|
|
27
|
+
/^sfp\d+$/.test(name) ||
|
|
28
|
+
/^sfp-sfpplus\d+$/.test(name) ||
|
|
29
|
+
/^combo\d+$/.test(name) ||
|
|
30
|
+
/^qsfp\d+$/.test(name);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Check if interface is a loopback
|
|
35
|
+
*/
|
|
36
|
+
export const isLoopback = (interfaceName: string): boolean => {
|
|
37
|
+
const name = interfaceName.toLowerCase();
|
|
38
|
+
return name === 'lo' || name.startsWith('loopback');
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check if interface is a bridge
|
|
43
|
+
*/
|
|
44
|
+
export const isBridgeInterface = (interfaceName: string): boolean => {
|
|
45
|
+
const name = interfaceName.toLowerCase();
|
|
46
|
+
return name.startsWith('bridge') || /^br\d+$/.test(name);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Check if interface is a VLAN
|
|
51
|
+
*/
|
|
52
|
+
export const isVlanInterface = (interfaceName: string): boolean => {
|
|
53
|
+
const name = interfaceName.toLowerCase();
|
|
54
|
+
return name.startsWith('vlan') || /^vlan\d+$/.test(name);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Check if interface is a bonding (LAG)
|
|
59
|
+
*/
|
|
60
|
+
export const isBondingInterface = (interfaceName: string): boolean => {
|
|
61
|
+
const name = interfaceName.toLowerCase();
|
|
62
|
+
return name.startsWith('bonding') || /^bond\d+$/.test(name);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Check if interface is WireGuard
|
|
67
|
+
*/
|
|
68
|
+
export const isWireGuardInterface = (interfaceName: string): boolean => {
|
|
69
|
+
const name = interfaceName.toLowerCase();
|
|
70
|
+
return name.startsWith('wireguard') || /^wg\d+$/.test(name);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Check if interface is a tunnel type
|
|
75
|
+
*/
|
|
76
|
+
export const isTunnelInterface = (interfaceName: string): boolean => {
|
|
77
|
+
const name = interfaceName.toLowerCase();
|
|
78
|
+
return (
|
|
79
|
+
name.startsWith('eoip') ||
|
|
80
|
+
name.startsWith('gre') ||
|
|
81
|
+
name.startsWith('ipip') ||
|
|
82
|
+
name.startsWith('vxlan') ||
|
|
83
|
+
name.startsWith('l2tp') ||
|
|
84
|
+
name.startsWith('pptp') ||
|
|
85
|
+
name.startsWith('sstp') ||
|
|
86
|
+
name.startsWith('ovpn') ||
|
|
87
|
+
name.startsWith('pppoe')
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Parse a MikroTik property value from a command string
|
|
93
|
+
* Example: parseProperty("add address=192.168.1.1/24 interface=LAN", "address") returns "192.168.1.1/24"
|
|
94
|
+
*/
|
|
95
|
+
export const parseProperty = (commandStr: string, propertyName: string): string | undefined => {
|
|
96
|
+
// Match property=value or property="value" or property='value'
|
|
97
|
+
const regex = new RegExp(`\\b${propertyName}=(?:"([^"]+)"|'([^']+)'|(\\S+))`, 'i');
|
|
98
|
+
const match = commandStr.match(regex);
|
|
99
|
+
if (match) {
|
|
100
|
+
return match[1] || match[2] || match[3];
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Check if a command/node has a specific property
|
|
107
|
+
*/
|
|
108
|
+
export const hasProperty = (nodeOrCommand: ConfigNode | string, propertyName: string): boolean => {
|
|
109
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
110
|
+
const regex = new RegExp(`\\b${propertyName}=`, 'i');
|
|
111
|
+
return regex.test(str);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get the firewall chain from a firewall rule command
|
|
116
|
+
*/
|
|
117
|
+
export const getFirewallChain = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
118
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
119
|
+
return parseProperty(str, 'chain');
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Get the firewall action from a firewall rule command
|
|
124
|
+
*/
|
|
125
|
+
export const getFirewallAction = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
126
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
127
|
+
return parseProperty(str, 'action');
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Get the interface from a command
|
|
132
|
+
*/
|
|
133
|
+
export const getInterface = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
134
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
135
|
+
// Try 'interface=' first, then 'in-interface=' or 'out-interface='
|
|
136
|
+
return parseProperty(str, 'interface') ||
|
|
137
|
+
parseProperty(str, 'in-interface') ||
|
|
138
|
+
parseProperty(str, 'out-interface');
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Get the comment from a command
|
|
143
|
+
*/
|
|
144
|
+
export const getComment = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
145
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
146
|
+
return parseProperty(str, 'comment');
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get the name property from a command
|
|
151
|
+
*/
|
|
152
|
+
export const getName = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
153
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
154
|
+
return parseProperty(str, 'name');
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Check if a command is an 'add' command
|
|
159
|
+
*/
|
|
160
|
+
export const isAddCommand = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
161
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
162
|
+
return /^add\s+/i.test(str.trim());
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Check if a command is a 'set' command
|
|
167
|
+
*/
|
|
168
|
+
export const isSetCommand = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
169
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
170
|
+
return /^set\s+/i.test(str.trim());
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get all 'add' commands from a node's children
|
|
175
|
+
*/
|
|
176
|
+
export const getAddCommands = (node: ConfigNode): ConfigNode[] => {
|
|
177
|
+
return node.children.filter((child) => isAddCommand(child));
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Get all 'set' commands from a node's children
|
|
182
|
+
*/
|
|
183
|
+
export const getSetCommands = (node: ConfigNode): ConfigNode[] => {
|
|
184
|
+
return node.children.filter((child) => isSetCommand(child));
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Check if a path block matches a specific path
|
|
189
|
+
* Example: isPathBlock(node, '/ip firewall filter') checks if node.id matches
|
|
190
|
+
*/
|
|
191
|
+
export const isPathBlock = (node: ConfigNode, path: string): boolean => {
|
|
192
|
+
const nodeId = node.id.toLowerCase().trim();
|
|
193
|
+
const targetPath = path.toLowerCase().trim();
|
|
194
|
+
return nodeId === targetPath || nodeId.startsWith(targetPath + ' ');
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Find a child node that matches a path pattern
|
|
199
|
+
*/
|
|
200
|
+
export const findPathBlock = (node: ConfigNode, pathPrefix: string): ConfigNode | undefined => {
|
|
201
|
+
return node.children.find((child) =>
|
|
202
|
+
child.id.toLowerCase().trim().startsWith(pathPrefix.toLowerCase())
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Find all child nodes that match a path pattern
|
|
208
|
+
*/
|
|
209
|
+
export const findPathBlocks = (node: ConfigNode, pathPrefix: string): ConfigNode[] => {
|
|
210
|
+
return node.children.filter((child) =>
|
|
211
|
+
child.id.toLowerCase().trim().startsWith(pathPrefix.toLowerCase())
|
|
212
|
+
);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Parse MikroTik address format (e.g., "192.168.1.1/24")
|
|
217
|
+
* @param address The address string with CIDR notation
|
|
218
|
+
* @returns Object with ip number, prefix length, and mask, or null if invalid
|
|
219
|
+
*/
|
|
220
|
+
export const parseMikroTikAddress = (
|
|
221
|
+
address: string
|
|
222
|
+
): { ip: number; prefix: number; mask: number } | null => {
|
|
223
|
+
// Remove quotes if present
|
|
224
|
+
const cleanAddress = address.replace(/['"]/g, '');
|
|
225
|
+
const parts = cleanAddress.split('/');
|
|
226
|
+
if (parts.length !== 2) return null;
|
|
227
|
+
|
|
228
|
+
const ipPart = parts[0];
|
|
229
|
+
const prefixPart = parts[1];
|
|
230
|
+
if (!ipPart || !prefixPart) return null;
|
|
231
|
+
|
|
232
|
+
const ip = parseIp(ipPart);
|
|
233
|
+
const prefix = parseInt(prefixPart, 10);
|
|
234
|
+
|
|
235
|
+
if (ip === null || isNaN(prefix) || prefix < 0 || prefix > 32) {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
ip,
|
|
241
|
+
prefix,
|
|
242
|
+
mask: prefixToMask(prefix),
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Get connection states from a firewall rule
|
|
248
|
+
* Example: "connection-state=established,related" returns ['established', 'related']
|
|
249
|
+
*/
|
|
250
|
+
export const getConnectionStates = (nodeOrCommand: ConfigNode | string): string[] => {
|
|
251
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
252
|
+
const states = parseProperty(str, 'connection-state');
|
|
253
|
+
if (!states) return [];
|
|
254
|
+
return states.split(',').map((s) => s.trim().toLowerCase());
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Check if a firewall rule has stateful tracking (established,related)
|
|
259
|
+
*/
|
|
260
|
+
export const hasStatefulTracking = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
261
|
+
const states = getConnectionStates(nodeOrCommand);
|
|
262
|
+
return states.includes('established') || states.includes('related');
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Get service port from /ip service command
|
|
267
|
+
*/
|
|
268
|
+
export const getServicePort = (nodeOrCommand: ConfigNode | string): number | undefined => {
|
|
269
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
270
|
+
const port = parseProperty(str, 'port');
|
|
271
|
+
if (port) {
|
|
272
|
+
const parsed = parseInt(port, 10);
|
|
273
|
+
return isNaN(parsed) ? undefined : parsed;
|
|
274
|
+
}
|
|
275
|
+
return undefined;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Check if a service is disabled
|
|
280
|
+
*/
|
|
281
|
+
export const isServiceDisabled = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
282
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
283
|
+
const disabled = parseProperty(str, 'disabled');
|
|
284
|
+
return disabled?.toLowerCase() === 'yes';
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Get all firewall rules from a firewall path block
|
|
289
|
+
*/
|
|
290
|
+
export const getFirewallRules = (firewallNode: ConfigNode): ConfigNode[] => {
|
|
291
|
+
return firewallNode.children.filter((child) => isAddCommand(child));
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Get NAT type from a NAT rule
|
|
296
|
+
*/
|
|
297
|
+
export const getNatAction = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
298
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
299
|
+
return parseProperty(str, 'action');
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Get out-interface from a NAT rule
|
|
304
|
+
*/
|
|
305
|
+
export const getOutInterface = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
306
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
307
|
+
return parseProperty(str, 'out-interface');
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Get in-interface from a rule
|
|
312
|
+
*/
|
|
313
|
+
export const getInInterface = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
314
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
315
|
+
return parseProperty(str, 'in-interface');
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Check if identity (hostname) is configured in a system identity block
|
|
320
|
+
*/
|
|
321
|
+
export const getSystemIdentity = (node: ConfigNode): string | undefined => {
|
|
322
|
+
// Look for "set name=..." in /system identity
|
|
323
|
+
for (const child of node.children) {
|
|
324
|
+
if (isSetCommand(child)) {
|
|
325
|
+
const name = getName(child);
|
|
326
|
+
if (name) return name;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return undefined;
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Check if NTP client is enabled
|
|
334
|
+
*/
|
|
335
|
+
export const isNtpEnabled = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
336
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
337
|
+
const enabled = parseProperty(str, 'enabled');
|
|
338
|
+
return enabled?.toLowerCase() === 'yes';
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Get NTP servers from /system ntp client servers block
|
|
343
|
+
*/
|
|
344
|
+
export const getNtpServers = (ntpNode: ConfigNode): string[] => {
|
|
345
|
+
const servers: string[] = [];
|
|
346
|
+
for (const child of ntpNode.children) {
|
|
347
|
+
if (isAddCommand(child)) {
|
|
348
|
+
const address = parseProperty(child.id, 'address');
|
|
349
|
+
if (address) servers.push(address);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return servers;
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Check if SSH strong-crypto is enabled
|
|
357
|
+
*/
|
|
358
|
+
export const isSshStrongCrypto = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
359
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
360
|
+
const strongCrypto = parseProperty(str, 'strong-crypto');
|
|
361
|
+
return strongCrypto?.toLowerCase() === 'yes';
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Get SSH host key type
|
|
366
|
+
*/
|
|
367
|
+
export const getSshHostKeyType = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
368
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
369
|
+
return parseProperty(str, 'host-key-type');
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Get SNMP community security level
|
|
374
|
+
*/
|
|
375
|
+
export const getSnmpSecurity = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
376
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
377
|
+
return parseProperty(str, 'security');
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Get SNMP community name
|
|
382
|
+
*/
|
|
383
|
+
export const getSnmpCommunityName = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
384
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
385
|
+
return parseProperty(str, 'name');
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Check if SNMP has authentication protocol configured
|
|
390
|
+
*/
|
|
391
|
+
export const hasSnmpAuthProtocol = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
392
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
393
|
+
return hasProperty(str, 'authentication-protocol');
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Check if SNMP has encryption protocol configured
|
|
398
|
+
*/
|
|
399
|
+
export const hasSnmpEncryptionProtocol = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
400
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
401
|
+
return hasProperty(str, 'encryption-protocol');
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Get allowed interface list property
|
|
406
|
+
*/
|
|
407
|
+
export const getAllowedInterfaceList = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
408
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
409
|
+
return parseProperty(str, 'allowed-interface-list');
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Get discover interface list from neighbor discovery settings
|
|
414
|
+
*/
|
|
415
|
+
export const getDiscoverInterfaceList = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
416
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
417
|
+
return parseProperty(str, 'discover-interface-list');
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Check if a feature is enabled (common pattern)
|
|
422
|
+
*/
|
|
423
|
+
export const isEnabled = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
424
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
425
|
+
const enabled = parseProperty(str, 'enabled');
|
|
426
|
+
return enabled?.toLowerCase() === 'yes';
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Check if MAC-Ping is enabled
|
|
431
|
+
*/
|
|
432
|
+
export const isMacPingEnabled = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
433
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
434
|
+
const enabled = parseProperty(str, 'enabled');
|
|
435
|
+
// Default is enabled if not explicitly disabled
|
|
436
|
+
return enabled?.toLowerCase() !== 'no';
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Get BGP TCP-MD5 key (checks if authentication is configured)
|
|
441
|
+
*/
|
|
442
|
+
export const getBgpTcpMd5Key = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
443
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
444
|
+
return parseProperty(str, 'tcp-md5-key');
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Get BGP remote AS
|
|
449
|
+
*/
|
|
450
|
+
export const getBgpRemoteAs = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
451
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
452
|
+
// RouterOS 7 uses remote.as, RouterOS 6 uses remote-as
|
|
453
|
+
return parseProperty(str, 'remote.as') || parseProperty(str, 'remote-as');
|
|
454
|
+
};
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Get BGP max prefix limit
|
|
458
|
+
*/
|
|
459
|
+
export const getBgpMaxPrefixLimit = (nodeOrCommand: ConfigNode | string): number | undefined => {
|
|
460
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
461
|
+
// RouterOS 7: input.limit-process-routes-ipv4
|
|
462
|
+
// RouterOS 6: max-prefix-limit
|
|
463
|
+
const limit = parseProperty(str, 'input.limit-process-routes-ipv4') ||
|
|
464
|
+
parseProperty(str, 'max-prefix-limit');
|
|
465
|
+
if (limit) {
|
|
466
|
+
const parsed = parseInt(limit, 10);
|
|
467
|
+
return isNaN(parsed) ? undefined : parsed;
|
|
468
|
+
}
|
|
469
|
+
return undefined;
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Check if BGP has input filter
|
|
474
|
+
*/
|
|
475
|
+
export const hasBgpInputFilter = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
476
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
477
|
+
// RouterOS 7: input.filter
|
|
478
|
+
// RouterOS 6: in-filter
|
|
479
|
+
return hasProperty(str, 'input.filter') || hasProperty(str, 'in-filter');
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Check if BGP has output filter
|
|
484
|
+
*/
|
|
485
|
+
export const hasBgpOutputFilter = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
486
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
487
|
+
// RouterOS 7: output.filter
|
|
488
|
+
// RouterOS 6: out-filter
|
|
489
|
+
return hasProperty(str, 'output.filter') || hasProperty(str, 'out-filter');
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Get OSPF authentication type
|
|
494
|
+
*/
|
|
495
|
+
export const getOspfAuth = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
496
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
497
|
+
return parseProperty(str, 'auth');
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Get OSPF authentication key
|
|
502
|
+
*/
|
|
503
|
+
export const getOspfAuthKey = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
504
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
505
|
+
return parseProperty(str, 'auth-key') || parseProperty(str, 'authentication-key');
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Get VRRP authentication type
|
|
510
|
+
*/
|
|
511
|
+
export const getVrrpAuth = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
512
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
513
|
+
return parseProperty(str, 'authentication');
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Get VRRP password
|
|
518
|
+
*/
|
|
519
|
+
export const getVrrpPassword = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
520
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
521
|
+
return parseProperty(str, 'password');
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Get IPsec encryption algorithm
|
|
526
|
+
*/
|
|
527
|
+
export const getIpsecEncAlgorithm = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
528
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
529
|
+
return parseProperty(str, 'enc-algorithm') || parseProperty(str, 'enc-algorithms');
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Get IPsec hash algorithm
|
|
534
|
+
*/
|
|
535
|
+
export const getIpsecHashAlgorithm = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
536
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
537
|
+
return parseProperty(str, 'hash-algorithm') || parseProperty(str, 'auth-algorithms');
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Get IPsec DH group
|
|
542
|
+
*/
|
|
543
|
+
export const getIpsecDhGroup = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
544
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
545
|
+
return parseProperty(str, 'dh-group') || parseProperty(str, 'pfs-group');
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Check if bridge has VLAN filtering enabled
|
|
550
|
+
*/
|
|
551
|
+
export const hasBridgeVlanFiltering = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
552
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
553
|
+
const vlanFiltering = parseProperty(str, 'vlan-filtering');
|
|
554
|
+
return vlanFiltering?.toLowerCase() === 'yes';
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Get bridge frame types
|
|
559
|
+
*/
|
|
560
|
+
export const getBridgeFrameTypes = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
561
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
562
|
+
return parseProperty(str, 'frame-types');
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Check if syslog (remote logging) is configured
|
|
567
|
+
*/
|
|
568
|
+
export const getSyslogTarget = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
569
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
570
|
+
return parseProperty(str, 'target');
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Get syslog remote address
|
|
575
|
+
*/
|
|
576
|
+
export const getSyslogRemote = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
577
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
578
|
+
return parseProperty(str, 'remote');
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Get address list name from a rule
|
|
583
|
+
*/
|
|
584
|
+
export const getAddressList = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
585
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
586
|
+
return parseProperty(str, 'address-list');
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Get source address list from a rule
|
|
591
|
+
*/
|
|
592
|
+
export const getSrcAddressList = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
593
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
594
|
+
return parseProperty(str, 'src-address-list');
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Get destination address list from a rule
|
|
599
|
+
*/
|
|
600
|
+
export const getDstAddressList = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
601
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
602
|
+
return parseProperty(str, 'dst-address-list');
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Check if firewall rule has logging enabled
|
|
607
|
+
*/
|
|
608
|
+
export const hasFirewallLogging = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
609
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
610
|
+
const log = parseProperty(str, 'log');
|
|
611
|
+
return log?.toLowerCase() === 'yes';
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* Get log prefix from a firewall rule
|
|
616
|
+
*/
|
|
617
|
+
export const getLogPrefix = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
618
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
619
|
+
return parseProperty(str, 'log-prefix');
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Get connection limit from a rule
|
|
624
|
+
*/
|
|
625
|
+
export const getConnectionLimit = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
626
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
627
|
+
return parseProperty(str, 'connection-limit');
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Get limit (rate limit) from a rule
|
|
632
|
+
*/
|
|
633
|
+
export const getRateLimit = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
634
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
635
|
+
return parseProperty(str, 'limit');
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Get TCP flags from a firewall rule
|
|
640
|
+
*/
|
|
641
|
+
export const getTcpFlags = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
642
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
643
|
+
return parseProperty(str, 'tcp-flags');
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Get destination port from a rule
|
|
648
|
+
*/
|
|
649
|
+
export const getDstPort = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
650
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
651
|
+
return parseProperty(str, 'dst-port');
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Get protocol from a rule
|
|
656
|
+
*/
|
|
657
|
+
export const getProtocol = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
658
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
659
|
+
return parseProperty(str, 'protocol');
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Check if IP cloud DDNS is enabled
|
|
664
|
+
*/
|
|
665
|
+
export const isCloudDdnsEnabled = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
666
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
667
|
+
const ddnsEnabled = parseProperty(str, 'ddns-enabled');
|
|
668
|
+
return ddnsEnabled?.toLowerCase() === 'yes';
|
|
669
|
+
};
|
|
670
|
+
|
|
671
|
+
/**
|
|
672
|
+
* Check if IP proxy is enabled
|
|
673
|
+
*/
|
|
674
|
+
export const isProxyEnabled = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
675
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
676
|
+
const enabled = parseProperty(str, 'enabled');
|
|
677
|
+
return enabled?.toLowerCase() === 'yes';
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Check if IP SOCKS is enabled
|
|
682
|
+
*/
|
|
683
|
+
export const isSocksEnabled = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
684
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
685
|
+
const enabled = parseProperty(str, 'enabled');
|
|
686
|
+
return enabled?.toLowerCase() === 'yes';
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Check if UPnP is enabled
|
|
691
|
+
*/
|
|
692
|
+
export const isUpnpEnabled = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
693
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
694
|
+
const enabled = parseProperty(str, 'enabled');
|
|
695
|
+
return enabled?.toLowerCase() === 'yes';
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Check if DNS allows remote requests
|
|
700
|
+
*/
|
|
701
|
+
export const isDnsAllowRemoteRequests = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
702
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
703
|
+
const allowRemote = parseProperty(str, 'allow-remote-requests');
|
|
704
|
+
return allowRemote?.toLowerCase() === 'yes';
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* Get system note content
|
|
709
|
+
*/
|
|
710
|
+
export const getSystemNote = (nodeOrCommand: ConfigNode | string): string | undefined => {
|
|
711
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
712
|
+
return parseProperty(str, 'note');
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Check if system note is shown at login
|
|
717
|
+
*/
|
|
718
|
+
export const isNoteShowAtLogin = (nodeOrCommand: ConfigNode | string): boolean => {
|
|
719
|
+
const str = typeof nodeOrCommand === 'string' ? nodeOrCommand : nodeOrCommand.id;
|
|
720
|
+
const showAtLogin = parseProperty(str, 'show-at-login');
|
|
721
|
+
return showAtLogin?.toLowerCase() === 'yes';
|
|
722
|
+
};
|