@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,1521 @@
|
|
|
1
|
+
// packages/core/src/parser/vendors/index.ts
|
|
2
|
+
|
|
3
|
+
import type { VendorSchema } from '../VendorSchema';
|
|
4
|
+
import { CiscoIOSSchema } from './cisco-ios';
|
|
5
|
+
import { CiscoNXOSSchema } from './cisco-nxos';
|
|
6
|
+
import { JuniperJunOSSchema } from './juniper-junos';
|
|
7
|
+
import { ArubaAOSCXSchema } from './aruba-aoscx';
|
|
8
|
+
import { ArubaAOSSwitchSchema } from './aruba-aosswitch';
|
|
9
|
+
import { ArubaWLCSchema } from './aruba-wlc';
|
|
10
|
+
import { PaloAltoPANOSSchema } from './paloalto-panos';
|
|
11
|
+
import { AristaEOSSchema } from './arista-eos';
|
|
12
|
+
import { VyOSSchema } from './vyos-vyos';
|
|
13
|
+
import { FortinetFortiGateSchema } from './fortinet-fortigate';
|
|
14
|
+
import { ExtremeEXOSSchema } from './extreme-exos';
|
|
15
|
+
import { ExtremeVOSSSchema } from './extreme-voss';
|
|
16
|
+
import { HuaweiVRPSchema } from './huawei-vrp';
|
|
17
|
+
import { MikroTikRouterOSSchema } from './mikrotik-routeros';
|
|
18
|
+
import { NokiaSROSSchema } from './nokia-sros';
|
|
19
|
+
import { CumulusLinuxSchema } from './cumulus-linux';
|
|
20
|
+
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// SEC-002: ReDoS-safe helper functions
|
|
23
|
+
// These replace potentially dangerous multiline regex patterns with
|
|
24
|
+
// line-by-line processing to prevent catastrophic backtracking.
|
|
25
|
+
// ============================================================================
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* SEC-002: Safe detection for FortiOS edit/next pattern.
|
|
29
|
+
* Replaces: /^config\s+\S+[\s\S]*?^\s+edit\s+/m with /^\s+next$/m
|
|
30
|
+
* which could cause ReDoS with crafted input.
|
|
31
|
+
*/
|
|
32
|
+
function hasFortiOSEditPattern(lines: string[]): boolean {
|
|
33
|
+
let inConfig = false;
|
|
34
|
+
let hasEdit = false;
|
|
35
|
+
for (const line of lines) {
|
|
36
|
+
if (/^config\s+\S+/.test(line)) {
|
|
37
|
+
inConfig = true;
|
|
38
|
+
}
|
|
39
|
+
if (inConfig && /^\s+edit\s+/.test(line)) {
|
|
40
|
+
hasEdit = true;
|
|
41
|
+
}
|
|
42
|
+
if (/^\s+next$/.test(line) && hasEdit) {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (/^end$/.test(line)) {
|
|
46
|
+
inConfig = false;
|
|
47
|
+
hasEdit = false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* SEC-002: Safe detection for FortiOS config/set/end pattern.
|
|
55
|
+
* Replaces: /^config\s+\S+[\s\S]*?^\s+set\s+\S+/m with /^end$/m
|
|
56
|
+
*/
|
|
57
|
+
function hasFortiOSSetPattern(lines: string[]): boolean {
|
|
58
|
+
let inConfig = false;
|
|
59
|
+
for (const line of lines) {
|
|
60
|
+
if (/^config\s+\S+/.test(line)) {
|
|
61
|
+
inConfig = true;
|
|
62
|
+
}
|
|
63
|
+
if (inConfig && /^\s+set\s+\S+/.test(line)) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
if (/^end$/.test(line)) {
|
|
67
|
+
inConfig = false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* SEC-002: Safe detection for Palo Alto network block with specific content.
|
|
75
|
+
* Replaces: /^\s*network\s*\{[\s\S]*?(ethernet\d+\/\d+|zone|virtual-router)/m
|
|
76
|
+
*/
|
|
77
|
+
function hasPaloAltoNetworkBlock(lines: string[]): boolean {
|
|
78
|
+
let inNetworkBlock = false;
|
|
79
|
+
let braceDepth = 0;
|
|
80
|
+
for (const line of lines) {
|
|
81
|
+
if (/^\s*network\s*\{/.test(line)) {
|
|
82
|
+
inNetworkBlock = true;
|
|
83
|
+
braceDepth = 1;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (inNetworkBlock) {
|
|
87
|
+
braceDepth += (line.match(/\{/g) || []).length;
|
|
88
|
+
braceDepth -= (line.match(/\}/g) || []).length;
|
|
89
|
+
if (/(ethernet\d+\/\d+|zone|virtual-router)/.test(line)) {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
if (braceDepth <= 0) {
|
|
93
|
+
inNetworkBlock = false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* SEC-002: Safe detection for Palo Alto security/nat rules block.
|
|
102
|
+
* Replaces: /^\s*(security|nat)\s*\{[\s\S]*?rules\s*\{/m
|
|
103
|
+
*/
|
|
104
|
+
function hasPaloAltoRulesBlock(lines: string[]): boolean {
|
|
105
|
+
let inSecurityOrNat = false;
|
|
106
|
+
let braceDepth = 0;
|
|
107
|
+
for (const line of lines) {
|
|
108
|
+
if (/^\s*(security|nat)\s*\{/.test(line)) {
|
|
109
|
+
inSecurityOrNat = true;
|
|
110
|
+
braceDepth = 1;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (inSecurityOrNat) {
|
|
114
|
+
braceDepth += (line.match(/\{/g) || []).length;
|
|
115
|
+
braceDepth -= (line.match(/\}/g) || []).length;
|
|
116
|
+
if (/rules\s*\{/.test(line)) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
if (braceDepth <= 0) {
|
|
120
|
+
inSecurityOrNat = false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* SEC-002: Safe detection for Palo Alto threat profiles block.
|
|
129
|
+
* Replaces: /^\s*profiles\s*\{[\s\S]*?(virus|spyware|vulnerability|url-filtering|wildfire-analysis)/m
|
|
130
|
+
*/
|
|
131
|
+
function hasPaloAltoProfilesBlock(lines: string[]): boolean {
|
|
132
|
+
let inProfiles = false;
|
|
133
|
+
let braceDepth = 0;
|
|
134
|
+
for (const line of lines) {
|
|
135
|
+
if (/^\s*profiles\s*\{/.test(line)) {
|
|
136
|
+
inProfiles = true;
|
|
137
|
+
braceDepth = 1;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (inProfiles) {
|
|
141
|
+
braceDepth += (line.match(/\{/g) || []).length;
|
|
142
|
+
braceDepth -= (line.match(/\}/g) || []).length;
|
|
143
|
+
if (/(virus|spyware|vulnerability|url-filtering|wildfire-analysis)/.test(line)) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
if (braceDepth <= 0) {
|
|
147
|
+
inProfiles = false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* SEC-002: Safe detection for VyOS service block with specific services.
|
|
156
|
+
* Replaces: /^\s*service\s*\{[\s\S]*?(ssh|dhcp-server|dns|https|lldp)/m
|
|
157
|
+
*/
|
|
158
|
+
function hasVyOSServiceBlock(lines: string[]): boolean {
|
|
159
|
+
let inService = false;
|
|
160
|
+
let braceDepth = 0;
|
|
161
|
+
for (const line of lines) {
|
|
162
|
+
if (/^\s*service\s*\{/.test(line)) {
|
|
163
|
+
inService = true;
|
|
164
|
+
braceDepth = 1;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (inService) {
|
|
168
|
+
braceDepth += (line.match(/\{/g) || []).length;
|
|
169
|
+
braceDepth -= (line.match(/\}/g) || []).length;
|
|
170
|
+
if (/(ssh|dhcp-server|dns|https|lldp)/.test(line)) {
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
if (braceDepth <= 0) {
|
|
174
|
+
inService = false;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* SEC-002: Safe detection for VyOS NAT with source/destination rules.
|
|
183
|
+
* Replaces: /^\s*nat\s*\{[\s\S]*?(source|destination)\s*\{[\s\S]*?rule\s+\d+/m
|
|
184
|
+
*/
|
|
185
|
+
function hasVyOSNatRuleBlock(lines: string[]): boolean {
|
|
186
|
+
let inNat = false;
|
|
187
|
+
let inSourceOrDest = false;
|
|
188
|
+
let braceDepth = 0;
|
|
189
|
+
for (const line of lines) {
|
|
190
|
+
if (/^\s*nat\s*\{/.test(line)) {
|
|
191
|
+
inNat = true;
|
|
192
|
+
braceDepth = 1;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (inNat) {
|
|
196
|
+
braceDepth += (line.match(/\{/g) || []).length;
|
|
197
|
+
braceDepth -= (line.match(/\}/g) || []).length;
|
|
198
|
+
if (/(source|destination)\s*\{/.test(line)) {
|
|
199
|
+
inSourceOrDest = true;
|
|
200
|
+
}
|
|
201
|
+
if (inSourceOrDest && /rule\s+\d+/.test(line)) {
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
if (braceDepth <= 0) {
|
|
205
|
+
inNat = false;
|
|
206
|
+
inSourceOrDest = false;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* SEC-002: Safe detection for VyOS ethernet interface block.
|
|
215
|
+
* Replaces: /^\s*interfaces\s*\{[\s\S]*?ethernet\s+eth\d+\s*\{/m
|
|
216
|
+
*/
|
|
217
|
+
function hasVyOSEthernetBlock(lines: string[]): boolean {
|
|
218
|
+
let inInterfaces = false;
|
|
219
|
+
let braceDepth = 0;
|
|
220
|
+
for (const line of lines) {
|
|
221
|
+
if (/^\s*interfaces\s*\{/.test(line)) {
|
|
222
|
+
inInterfaces = true;
|
|
223
|
+
braceDepth = 1;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (inInterfaces) {
|
|
227
|
+
braceDepth += (line.match(/\{/g) || []).length;
|
|
228
|
+
braceDepth -= (line.match(/\}/g) || []).length;
|
|
229
|
+
if (/ethernet\s+eth\d+\s*\{/.test(line)) {
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
if (braceDepth <= 0) {
|
|
233
|
+
inInterfaces = false;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* SEC-002: Safe detection for VyOS firewall name ruleset.
|
|
242
|
+
* Replaces: /^\s*firewall\s*\{[\s\S]*?name\s+\S+\s*\{[\s\S]*?rule\s+\d+/m
|
|
243
|
+
*/
|
|
244
|
+
function hasVyOSFirewallRuleBlock(lines: string[]): boolean {
|
|
245
|
+
let inFirewall = false;
|
|
246
|
+
let inName = false;
|
|
247
|
+
let braceDepth = 0;
|
|
248
|
+
for (const line of lines) {
|
|
249
|
+
if (/^\s*firewall\s*\{/.test(line)) {
|
|
250
|
+
inFirewall = true;
|
|
251
|
+
braceDepth = 1;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (inFirewall) {
|
|
255
|
+
braceDepth += (line.match(/\{/g) || []).length;
|
|
256
|
+
braceDepth -= (line.match(/\}/g) || []).length;
|
|
257
|
+
if (/name\s+\S+\s*\{/.test(line)) {
|
|
258
|
+
inName = true;
|
|
259
|
+
}
|
|
260
|
+
if (inName && /rule\s+\d+/.test(line)) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
if (braceDepth <= 0) {
|
|
264
|
+
inFirewall = false;
|
|
265
|
+
inName = false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* SEC-002: Safe detection for VyOS high-availability/VRRP block.
|
|
274
|
+
* Replaces: /^\s*high-availability\s*\{[\s\S]*?vrrp\s*\{/m
|
|
275
|
+
*/
|
|
276
|
+
function hasVyOSHighAvailabilityBlock(lines: string[]): boolean {
|
|
277
|
+
let inHA = false;
|
|
278
|
+
let braceDepth = 0;
|
|
279
|
+
for (const line of lines) {
|
|
280
|
+
if (/^\s*high-availability\s*\{/.test(line)) {
|
|
281
|
+
inHA = true;
|
|
282
|
+
braceDepth = 1;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (inHA) {
|
|
286
|
+
braceDepth += (line.match(/\{/g) || []).length;
|
|
287
|
+
braceDepth -= (line.match(/\}/g) || []).length;
|
|
288
|
+
if (/vrrp\s*\{/.test(line)) {
|
|
289
|
+
return true;
|
|
290
|
+
}
|
|
291
|
+
if (braceDepth <= 0) {
|
|
292
|
+
inHA = false;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* SEC-002: Safe detection for VyOS VPN IPsec site-to-site.
|
|
301
|
+
* Replaces: /^\s*vpn\s*\{[\s\S]*?ipsec\s*\{[\s\S]*?site-to-site/m
|
|
302
|
+
*/
|
|
303
|
+
function hasVyOSVpnIpsecBlock(lines: string[]): boolean {
|
|
304
|
+
let inVpn = false;
|
|
305
|
+
let inIpsec = false;
|
|
306
|
+
let braceDepth = 0;
|
|
307
|
+
for (const line of lines) {
|
|
308
|
+
if (/^\s*vpn\s*\{/.test(line)) {
|
|
309
|
+
inVpn = true;
|
|
310
|
+
braceDepth = 1;
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (inVpn) {
|
|
314
|
+
braceDepth += (line.match(/\{/g) || []).length;
|
|
315
|
+
braceDepth -= (line.match(/\}/g) || []).length;
|
|
316
|
+
if (/ipsec\s*\{/.test(line)) {
|
|
317
|
+
inIpsec = true;
|
|
318
|
+
}
|
|
319
|
+
if (inIpsec && /site-to-site/.test(line)) {
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
if (braceDepth <= 0) {
|
|
323
|
+
inVpn = false;
|
|
324
|
+
inIpsec = false;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* SEC-002: Safe detection for VyOS protocols static routes.
|
|
333
|
+
* Replaces: /^\s*protocols\s*\{[\s\S]*?static\s*\{[\s\S]*?route\s+[\d.\/]+\s*\{/m
|
|
334
|
+
*/
|
|
335
|
+
function hasVyOSStaticRouteBlock(lines: string[]): boolean {
|
|
336
|
+
let inProtocols = false;
|
|
337
|
+
let inStatic = false;
|
|
338
|
+
let braceDepth = 0;
|
|
339
|
+
for (const line of lines) {
|
|
340
|
+
if (/^\s*protocols\s*\{/.test(line)) {
|
|
341
|
+
inProtocols = true;
|
|
342
|
+
braceDepth = 1;
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (inProtocols) {
|
|
346
|
+
braceDepth += (line.match(/\{/g) || []).length;
|
|
347
|
+
braceDepth -= (line.match(/\}/g) || []).length;
|
|
348
|
+
if (/static\s*\{/.test(line)) {
|
|
349
|
+
inStatic = true;
|
|
350
|
+
}
|
|
351
|
+
if (inStatic && /route\s+[\d.\/]+\s*\{/.test(line)) {
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
if (braceDepth <= 0) {
|
|
355
|
+
inProtocols = false;
|
|
356
|
+
inStatic = false;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* SEC-002: Safe detection for Nokia SR OS router block with interface.
|
|
365
|
+
* Replaces: /^\s+router\s*[\s\S]*?interface\s+"[^"]+"/m
|
|
366
|
+
*/
|
|
367
|
+
function hasNokiaRouterInterfaceBlock(lines: string[]): boolean {
|
|
368
|
+
let inRouter = false;
|
|
369
|
+
for (const line of lines) {
|
|
370
|
+
if (/^\s+router\s*(".*")?$/.test(line)) {
|
|
371
|
+
inRouter = true;
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
if (inRouter) {
|
|
375
|
+
if (/interface\s+"[^"]+"/.test(line)) {
|
|
376
|
+
return true;
|
|
377
|
+
}
|
|
378
|
+
// Exit router block on unindented line (excluding blank lines)
|
|
379
|
+
if (line.trim() && !/^\s/.test(line)) {
|
|
380
|
+
inRouter = false;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* SEC-002: Safe detection for Nokia SR OS system name.
|
|
389
|
+
* Replaces: /^\s+system[\s\S]*?name\s+"[^"]+"/m
|
|
390
|
+
*/
|
|
391
|
+
function hasNokiaSystemNameBlock(lines: string[]): boolean {
|
|
392
|
+
let inSystem = false;
|
|
393
|
+
for (const line of lines) {
|
|
394
|
+
if (/^\s+system\s*$/.test(line)) {
|
|
395
|
+
inSystem = true;
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
if (inSystem) {
|
|
399
|
+
if (/name\s+"[^"]+"/.test(line)) {
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
if (line.trim() && !/^\s/.test(line)) {
|
|
403
|
+
inSystem = false;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* SEC-002: Safe detection for Nokia SR OS BGP group.
|
|
412
|
+
* Replaces: /^\s+bgp[\s\S]*?group\s+"[^"]+"/m
|
|
413
|
+
*/
|
|
414
|
+
function hasNokiaBgpGroupBlock(lines: string[]): boolean {
|
|
415
|
+
let inBgp = false;
|
|
416
|
+
for (const line of lines) {
|
|
417
|
+
if (/^\s+bgp\s*$/.test(line)) {
|
|
418
|
+
inBgp = true;
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
if (inBgp) {
|
|
422
|
+
if (/group\s+"[^"]+"/.test(line)) {
|
|
423
|
+
return true;
|
|
424
|
+
}
|
|
425
|
+
if (line.trim() && !/^\s/.test(line)) {
|
|
426
|
+
inBgp = false;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
return false;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* SEC-002: Safe detection for Nokia SR OS port with admin-state.
|
|
435
|
+
* Replaces: /^port\s+\d+\/\d+\/\d+[\s\S]*?admin-state/m
|
|
436
|
+
*/
|
|
437
|
+
function hasNokiaPortAdminState(lines: string[]): boolean {
|
|
438
|
+
let inPort = false;
|
|
439
|
+
for (const line of lines) {
|
|
440
|
+
if (/^port\s+\d+\/\d+\/\d+/.test(line)) {
|
|
441
|
+
inPort = true;
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
if (inPort) {
|
|
445
|
+
if (/admin-state/.test(line)) {
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
// Exit port block on non-indented line
|
|
449
|
+
if (line.trim() && !/^\s/.test(line)) {
|
|
450
|
+
inPort = false;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return false;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* SEC-002: Safe detection for Nokia SR OS card/MDA.
|
|
459
|
+
* Replaces: /^card\s+\d+[\s\S]*?mda\s+\d+/m
|
|
460
|
+
*/
|
|
461
|
+
function hasNokiaCardMdaBlock(lines: string[]): boolean {
|
|
462
|
+
let inCard = false;
|
|
463
|
+
for (const line of lines) {
|
|
464
|
+
if (/^card\s+\d+/.test(line)) {
|
|
465
|
+
inCard = true;
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
if (inCard) {
|
|
469
|
+
if (/mda\s+\d+/.test(line)) {
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
if (line.trim() && !/^\s/.test(line)) {
|
|
473
|
+
inCard = false;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* SEC-002: Safe detection for VOSS router isis with SPBM.
|
|
482
|
+
* Replaces: /^router\s+isis[\s\S]*?spbm\s+\d+/m
|
|
483
|
+
*/
|
|
484
|
+
function hasVossRouterIsisSpbm(lines: string[]): boolean {
|
|
485
|
+
let inIsis = false;
|
|
486
|
+
for (const line of lines) {
|
|
487
|
+
if (/^router\s+isis/.test(line)) {
|
|
488
|
+
inIsis = true;
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
491
|
+
if (inIsis) {
|
|
492
|
+
if (/spbm\s+\d+/.test(line)) {
|
|
493
|
+
return true;
|
|
494
|
+
}
|
|
495
|
+
// Exit on another top-level command
|
|
496
|
+
if (line.trim() && !/^\s/.test(line) && !/^!/.test(line)) {
|
|
497
|
+
inIsis = false;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
return false;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* SEC-002: Safe detection for Huawei AAA block.
|
|
506
|
+
* Replaces: /^aaa\s*$/m with /^\s+(authentication-scheme|authorization-scheme|local-user)/m
|
|
507
|
+
*/
|
|
508
|
+
function hasHuaweiAaaBlock(lines: string[]): boolean {
|
|
509
|
+
let inAaa = false;
|
|
510
|
+
for (const line of lines) {
|
|
511
|
+
if (/^aaa\s*$/.test(line)) {
|
|
512
|
+
inAaa = true;
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (inAaa) {
|
|
516
|
+
if (/^\s+(authentication-scheme|authorization-scheme|local-user)/.test(line)) {
|
|
517
|
+
return true;
|
|
518
|
+
}
|
|
519
|
+
if (line.trim() && !/^\s/.test(line) && !/^#/.test(line)) {
|
|
520
|
+
inAaa = false;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return false;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/** All registered vendor schemas */
|
|
528
|
+
export const vendorSchemas: VendorSchema[] = [
|
|
529
|
+
CiscoIOSSchema,
|
|
530
|
+
CiscoNXOSSchema,
|
|
531
|
+
JuniperJunOSSchema,
|
|
532
|
+
ArubaAOSCXSchema,
|
|
533
|
+
ArubaAOSSwitchSchema,
|
|
534
|
+
ArubaWLCSchema,
|
|
535
|
+
PaloAltoPANOSSchema,
|
|
536
|
+
AristaEOSSchema,
|
|
537
|
+
VyOSSchema,
|
|
538
|
+
FortinetFortiGateSchema,
|
|
539
|
+
ExtremeEXOSSchema,
|
|
540
|
+
ExtremeVOSSSchema,
|
|
541
|
+
HuaweiVRPSchema,
|
|
542
|
+
MikroTikRouterOSSchema,
|
|
543
|
+
NokiaSROSSchema,
|
|
544
|
+
CumulusLinuxSchema,
|
|
545
|
+
];
|
|
546
|
+
|
|
547
|
+
/** Default vendor when none specified or detection fails */
|
|
548
|
+
export const defaultVendor = CiscoIOSSchema;
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Get vendor schema by ID.
|
|
552
|
+
* @param vendorId The vendor identifier (e.g., 'cisco-ios', 'juniper-junos')
|
|
553
|
+
* @returns The matching VendorSchema
|
|
554
|
+
* @throws Error if vendor not found
|
|
555
|
+
*/
|
|
556
|
+
export function getVendor(vendorId: string): VendorSchema {
|
|
557
|
+
const vendor = vendorSchemas.find((v) => v.id === vendorId);
|
|
558
|
+
if (!vendor) {
|
|
559
|
+
const available = vendorSchemas.map((v) => v.id).join(', ');
|
|
560
|
+
throw new Error(`Unknown vendor: ${vendorId}. Available: ${available}`);
|
|
561
|
+
}
|
|
562
|
+
return vendor;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* Check if a vendor ID is valid.
|
|
567
|
+
* @param vendorId The vendor identifier to check
|
|
568
|
+
* @returns true if the vendor exists
|
|
569
|
+
*/
|
|
570
|
+
export function isValidVendor(vendorId: string): boolean {
|
|
571
|
+
return vendorSchemas.some((v) => v.id === vendorId);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Get all available vendor IDs.
|
|
576
|
+
* @returns Array of vendor identifiers
|
|
577
|
+
*/
|
|
578
|
+
export function getAvailableVendors(): string[] {
|
|
579
|
+
return vendorSchemas.map((v) => v.id);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Vendor info for display purposes.
|
|
584
|
+
*/
|
|
585
|
+
export interface VendorInfo {
|
|
586
|
+
id: string;
|
|
587
|
+
name: string;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Get all available vendors with their display names.
|
|
592
|
+
* @returns Array of vendor info objects
|
|
593
|
+
*/
|
|
594
|
+
export function getAvailableVendorInfo(): VendorInfo[] {
|
|
595
|
+
return vendorSchemas.map((v) => ({ id: v.id, name: v.name }));
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Auto-detect vendor from configuration text.
|
|
600
|
+
* Uses heuristics based on syntax patterns unique to each vendor.
|
|
601
|
+
*
|
|
602
|
+
* Detection priority:
|
|
603
|
+
* 1. Juniper JunOS - brace-based hierarchy, set commands
|
|
604
|
+
* 2. Aruba WLC - profile-based WLAN configuration
|
|
605
|
+
* 3. Aruba AOS-CX - modern switch syntax
|
|
606
|
+
* 4. Aruba AOS-Switch - legacy ProCurve syntax
|
|
607
|
+
* 5. Cisco NX-OS - feature commands, VDC
|
|
608
|
+
* 6. Cisco IOS - default fallback
|
|
609
|
+
*
|
|
610
|
+
* SEC-002: ReDoS protection implemented via:
|
|
611
|
+
* - Reduced sample size (2000 chars for initial pass)
|
|
612
|
+
* - Line-by-line processing for complex pattern detection
|
|
613
|
+
* - Replaced dangerous [\s\S]*? patterns with safe helper functions
|
|
614
|
+
*
|
|
615
|
+
* @param configText The configuration text to analyze
|
|
616
|
+
* @returns The detected VendorSchema (defaults to Cisco IOS)
|
|
617
|
+
*/
|
|
618
|
+
export function detectVendor(configText: string): VendorSchema {
|
|
619
|
+
// SEC-002: Analyze first portion of config for detection patterns
|
|
620
|
+
// Reduced from 4000 to 2000 chars for better ReDoS protection
|
|
621
|
+
const sampleText = configText.slice(0, 2000);
|
|
622
|
+
|
|
623
|
+
// SEC-002: Pre-split lines for safe helper functions
|
|
624
|
+
// This is done once and reused by multiple detection functions
|
|
625
|
+
const lines = sampleText.split('\n');
|
|
626
|
+
|
|
627
|
+
// ============ NVIDIA Cumulus Linux Detection ============
|
|
628
|
+
// Cumulus uses NCLU (net add/del), NVUE (nv set/unset), or Debian-style ifupdown2
|
|
629
|
+
// Must be checked early due to unique command prefixes
|
|
630
|
+
|
|
631
|
+
// NCLU commands: net add interface, net add bgp, net add vlan
|
|
632
|
+
if (/^net\s+(add|del)\s+(interface|bgp|ospf|vlan|bond|bridge|clag|routing|loopback)\s+/m.test(sampleText)) {
|
|
633
|
+
return CumulusLinuxSchema;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// NVUE commands: nv set interface, nv set router bgp, nv set bridge
|
|
637
|
+
if (/^nv\s+(set|unset)\s+(interface|router|bridge|vrf|system|service|evpn|nve|qos)\s+/m.test(sampleText)) {
|
|
638
|
+
return CumulusLinuxSchema;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// NVUE config commands: nv config apply, nv config save
|
|
642
|
+
if (/^nv\s+config\s+(apply|save|diff|patch|replace)/m.test(sampleText)) {
|
|
643
|
+
return CumulusLinuxSchema;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
// Cumulus-specific interface naming: swpN (switch ports)
|
|
647
|
+
// Combined with Debian ifupdown2 syntax
|
|
648
|
+
if (/^auto\s+swp\d+/m.test(sampleText) || /^iface\s+swp\d+/m.test(sampleText)) {
|
|
649
|
+
return CumulusLinuxSchema;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Cumulus MLAG (CLAG) configuration
|
|
653
|
+
if (/^net\s+add\s+clag\s+peer/m.test(sampleText) || /^clagd-/m.test(sampleText)) {
|
|
654
|
+
return CumulusLinuxSchema;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Cumulus bridge configuration with bridge-vids, bridge-pvid (VLAN-aware bridge)
|
|
658
|
+
if (/^\s+bridge-vids\s+/m.test(sampleText) && /^\s+bridge-pvid\s+/m.test(sampleText)) {
|
|
659
|
+
return CumulusLinuxSchema;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// Cumulus bridge-vlan-aware directive (distinctive)
|
|
663
|
+
if (/^\s+bridge-vlan-aware\s+yes/m.test(sampleText)) {
|
|
664
|
+
return CumulusLinuxSchema;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Cumulus peerlink interface (MLAG)
|
|
668
|
+
if (/^auto\s+peerlink/m.test(sampleText) || /^iface\s+peerlink/m.test(sampleText)) {
|
|
669
|
+
return CumulusLinuxSchema;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Cumulus bond with clag-id
|
|
673
|
+
if (/^\s+clag-id\s+\d+/m.test(sampleText)) {
|
|
674
|
+
return CumulusLinuxSchema;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Cumulus vlan-raw-device directive
|
|
678
|
+
if (/^\s+vlan-raw-device\s+/m.test(sampleText)) {
|
|
679
|
+
return CumulusLinuxSchema;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// ============ MikroTik RouterOS Detection ============
|
|
683
|
+
// RouterOS uses distinctive path-based syntax with forward slashes
|
|
684
|
+
// Must be checked early as paths like /ip could be confused with comments
|
|
685
|
+
|
|
686
|
+
// MikroTik interface paths: /interface ethernet, /interface vlan, /interface bridge
|
|
687
|
+
if (/^\/interface\s+(ethernet|vlan|bridge|wireless|bonding|wireguard)/m.test(sampleText)) {
|
|
688
|
+
return MikroTikRouterOSSchema;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
// MikroTik IP configuration: /ip address, /ip firewall, /ip route, /ip dns
|
|
692
|
+
if (/^\/ip\s+(address|firewall|route|dns|pool|dhcp-server|dhcp-client|service)/m.test(sampleText)) {
|
|
693
|
+
return MikroTikRouterOSSchema;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// MikroTik system identity (hostname equivalent)
|
|
697
|
+
if (/^\/system\s+identity/m.test(sampleText)) {
|
|
698
|
+
return MikroTikRouterOSSchema;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// MikroTik routing protocols
|
|
702
|
+
if (/^\/routing\s+(bgp|ospf|filter|bfd|id)/m.test(sampleText)) {
|
|
703
|
+
return MikroTikRouterOSSchema;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// MikroTik user management
|
|
707
|
+
if (/^\/user\s*$/m.test(sampleText) || /^\/user\s+group/m.test(sampleText)) {
|
|
708
|
+
return MikroTikRouterOSSchema;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// MikroTik queue configuration
|
|
712
|
+
if (/^\/queue\s+(simple|tree|type)/m.test(sampleText)) {
|
|
713
|
+
return MikroTikRouterOSSchema;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
// MikroTik tools
|
|
717
|
+
if (/^\/tool\s+(bandwidth-server|netwatch|mac-server|e-mail|graphing)/m.test(sampleText)) {
|
|
718
|
+
return MikroTikRouterOSSchema;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// MikroTik CAPsMAN (wireless controller)
|
|
722
|
+
if (/^\/caps-man\s/m.test(sampleText)) {
|
|
723
|
+
return MikroTikRouterOSSchema;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// MikroTik distinctive find expression syntax: [ find default-name=ether1 ]
|
|
727
|
+
if (/\[\s*find\s+[a-z-]+=["']?[^\]]+["']?\s*\]/m.test(sampleText)) {
|
|
728
|
+
return MikroTikRouterOSSchema;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// MikroTik add/set commands with property=value syntax under path blocks
|
|
732
|
+
// Distinctive pattern: add chain=input action=accept
|
|
733
|
+
if (/^add\s+[a-z-]+=\S+.*[a-z-]+=\S+/m.test(sampleText) && /^\/[a-z]/m.test(sampleText)) {
|
|
734
|
+
return MikroTikRouterOSSchema;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// MikroTik SNMP and certificates
|
|
738
|
+
if (/^\/snmp\s*$/m.test(sampleText) || /^\/certificate\s*$/m.test(sampleText)) {
|
|
739
|
+
return MikroTikRouterOSSchema;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// MikroTik PPP configuration
|
|
743
|
+
if (/^\/ppp\s+(profile|secret|aaa)/m.test(sampleText)) {
|
|
744
|
+
return MikroTikRouterOSSchema;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
// MikroTik system logging, NTP, scheduler
|
|
748
|
+
if (/^\/system\s+(logging|ntp|scheduler|script|clock)/m.test(sampleText)) {
|
|
749
|
+
return MikroTikRouterOSSchema;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// ============ Fortinet FortiGate (FortiOS) Detection ============
|
|
753
|
+
// FortiOS uses distinctive config/edit/next/end syntax
|
|
754
|
+
|
|
755
|
+
// FortiOS config blocks: "config system global", "config firewall policy"
|
|
756
|
+
if (/^config\s+system\s+(global|interface|admin|dns|ntp|ha|settings)/m.test(sampleText)) {
|
|
757
|
+
return FortinetFortiGateSchema;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// FortiOS firewall config: "config firewall policy", "config firewall address"
|
|
761
|
+
if (/^config\s+firewall\s+(policy|address|addrgrp|service|vip|ippool)/m.test(sampleText)) {
|
|
762
|
+
return FortinetFortiGateSchema;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// FortiOS VPN config: "config vpn ipsec phase1-interface"
|
|
766
|
+
if (/^config\s+vpn\s+(ipsec|ssl)/m.test(sampleText)) {
|
|
767
|
+
return FortinetFortiGateSchema;
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
// FortiOS router config: "config router static", "config router bgp"
|
|
771
|
+
if (/^config\s+router\s+(static|bgp|ospf|policy|rip|access-list|prefix-list|route-map)/m.test(sampleText)) {
|
|
772
|
+
return FortinetFortiGateSchema;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// FortiOS security profiles: "config antivirus profile", "config webfilter profile"
|
|
776
|
+
if (/^config\s+(antivirus|webfilter|ips|application|dlp|spamfilter|emailfilter|dnsfilter|waf|voip)\s+/m.test(sampleText)) {
|
|
777
|
+
return FortinetFortiGateSchema;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// FortiOS user config: "config user local", "config user ldap"
|
|
781
|
+
if (/^config\s+user\s+(local|group|ldap|radius|tacacs|fsso)/m.test(sampleText)) {
|
|
782
|
+
return FortinetFortiGateSchema;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// FortiOS log config: "config log syslogd setting"
|
|
786
|
+
if (/^config\s+log\s+(syslogd|fortianalyzer|disk|memory)/m.test(sampleText)) {
|
|
787
|
+
return FortinetFortiGateSchema;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// FortiOS edit with next pattern (very distinctive)
|
|
791
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
792
|
+
if (hasFortiOSEditPattern(lines)) {
|
|
793
|
+
return FortinetFortiGateSchema;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// FortiOS set commands within config blocks
|
|
797
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
798
|
+
if (hasFortiOSSetPattern(lines) && /^end$/m.test(sampleText)) {
|
|
799
|
+
return FortinetFortiGateSchema;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// ============ Palo Alto PAN-OS Detection ============
|
|
803
|
+
// PAN-OS uses distinctive top-level stanzas and set commands
|
|
804
|
+
|
|
805
|
+
// Palo Alto hierarchical format: "deviceconfig {", "rulebase {"
|
|
806
|
+
if (/^\s*(deviceconfig|rulebase|mgt-config|vsys\d*)\s*\{/m.test(sampleText)) {
|
|
807
|
+
return PaloAltoPANOSSchema;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// Palo Alto network config with zone or interface naming
|
|
811
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
812
|
+
if (hasPaloAltoNetworkBlock(lines)) {
|
|
813
|
+
return PaloAltoPANOSSchema;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// Palo Alto set commands format
|
|
817
|
+
// Note: 'service' in Palo Alto refers to service objects (HTTP, HTTPS, etc.)
|
|
818
|
+
// NOT service daemons like VyOS (service ssh, service dhcp-server)
|
|
819
|
+
// Palo Alto service objects: "set service <name> protocol tcp port <port>"
|
|
820
|
+
if (/^set\s+(deviceconfig|rulebase|network\s+interface\s+ethernet|address|zone)\s+/m.test(sampleText)) {
|
|
821
|
+
return PaloAltoPANOSSchema;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Palo Alto service objects (more specific pattern)
|
|
825
|
+
if (/^set\s+service\s+\S+\s+protocol\s+(tcp|udp)/m.test(sampleText)) {
|
|
826
|
+
return PaloAltoPANOSSchema;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// Palo Alto security rules format
|
|
830
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
831
|
+
if (hasPaloAltoRulesBlock(lines)) {
|
|
832
|
+
return PaloAltoPANOSSchema;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// Palo Alto threat profiles
|
|
836
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
837
|
+
if (hasPaloAltoProfilesBlock(lines)) {
|
|
838
|
+
return PaloAltoPANOSSchema;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// Palo Alto GlobalProtect
|
|
842
|
+
if (/^\s*global-protect\s*\{/m.test(sampleText)) {
|
|
843
|
+
return PaloAltoPANOSSchema;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// Panorama specific constructs
|
|
847
|
+
if (/^\s*(device-group|template|template-stack|shared)\s*\{/m.test(sampleText)) {
|
|
848
|
+
return PaloAltoPANOSSchema;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// ============ VyOS/EdgeOS Detection ============
|
|
852
|
+
// VyOS uses brace-based hierarchy with distinctive top-level stanzas
|
|
853
|
+
// Must be checked before JunOS since both use braces and 'set' commands
|
|
854
|
+
|
|
855
|
+
// VyOS set commands with distinctive paths
|
|
856
|
+
// VyOS uses 'set interfaces ethernet' (not 'set interfaces ge-')
|
|
857
|
+
if (/^set\s+(interfaces\s+ethernet|service\s+ssh|nat\s+source|firewall\s+name|high-availability|vpn\s+ipsec|traffic-policy|container\s+name)\s+/m.test(sampleText)) {
|
|
858
|
+
return VyOSSchema;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// VyOS hierarchical format with distinctive stanzas
|
|
862
|
+
// 'service' and 'nat' as top-level are VyOS-specific (not JunOS)
|
|
863
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
864
|
+
if (hasVyOSServiceBlock(lines)) {
|
|
865
|
+
return VyOSSchema;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// VyOS NAT structure (source/destination rules)
|
|
869
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
870
|
+
if (hasVyOSNatRuleBlock(lines)) {
|
|
871
|
+
return VyOSSchema;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// VyOS ethernet interface naming (eth0, eth1, etc.)
|
|
875
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
876
|
+
if (hasVyOSEthernetBlock(lines)) {
|
|
877
|
+
return VyOSSchema;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// VyOS set commands for ethernet interfaces
|
|
881
|
+
if (/^set\s+interfaces\s+ethernet\s+eth\d+/m.test(sampleText)) {
|
|
882
|
+
return VyOSSchema;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
// VyOS firewall name ruleset (vs JunOS filter)
|
|
886
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
887
|
+
if (hasVyOSFirewallRuleBlock(lines)) {
|
|
888
|
+
return VyOSSchema;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
// VyOS zone-based firewall
|
|
892
|
+
if (/^set\s+firewall\s+zone\s+/m.test(sampleText)) {
|
|
893
|
+
return VyOSSchema;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
// VyOS bonding/bridge interfaces (distinctive names)
|
|
897
|
+
if (/^set\s+interfaces\s+(bonding\s+bond\d+|bridge\s+br\d+|wireguard\s+wg\d+)/m.test(sampleText)) {
|
|
898
|
+
return VyOSSchema;
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// VyOS high-availability/VRRP structure
|
|
902
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
903
|
+
if (hasVyOSHighAvailabilityBlock(lines)) {
|
|
904
|
+
return VyOSSchema;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// VyOS VPN IPsec site-to-site
|
|
908
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
909
|
+
if (hasVyOSVpnIpsecBlock(lines)) {
|
|
910
|
+
return VyOSSchema;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// VyOS protocols static routes structure
|
|
914
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
915
|
+
if (hasVyOSStaticRouteBlock(lines)) {
|
|
916
|
+
return VyOSSchema;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// VyOS/EdgeOS comment format /* comment */
|
|
920
|
+
if (/^\/\*\s*.+\s*\*\/$/m.test(sampleText) && /^\s*(interfaces|firewall|nat|service|protocols)\s*\{/m.test(sampleText)) {
|
|
921
|
+
return VyOSSchema;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// ============ Juniper JunOS Detection ============
|
|
925
|
+
// JunOS uses brace-based hierarchy and has distinctive top-level stanzas
|
|
926
|
+
|
|
927
|
+
// Hierarchical format with braces: "system {", "interfaces {"
|
|
928
|
+
// These patterns are unique to JunOS display format
|
|
929
|
+
if (/^\s*(system|chassis|interfaces|protocols|policy-options|routing-options|routing-instances|security|firewall|class-of-service|vlans|bridge-domains)\s*\{/m.test(sampleText)) {
|
|
930
|
+
return JuniperJunOSSchema;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// Set commands format: "set interfaces ge-0/0/0"
|
|
934
|
+
// JunOS flat configuration format
|
|
935
|
+
if (/^set\s+(system|chassis|interfaces|protocols|policy-options|routing-options|routing-instances|security|firewall)/m.test(sampleText)) {
|
|
936
|
+
return JuniperJunOSSchema;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// JunOS-style interface names (ge-, xe-, et-, ae-, lo0, etc.)
|
|
940
|
+
// Combined with brace on same line or next line
|
|
941
|
+
if (/^\s*(ge|xe|et|ae|lo|irb|vlan|em|fxp)-[\d\/:.]+\s*\{/m.test(sampleText)) {
|
|
942
|
+
return JuniperJunOSSchema;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// JunOS version statement
|
|
946
|
+
if (/^version\s+[\d.]+[A-Z]\d+/m.test(sampleText)) {
|
|
947
|
+
return JuniperJunOSSchema;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// ============ Aruba WLC Detection ============
|
|
951
|
+
// ArubaOS WLC uses profile-based WLAN configuration
|
|
952
|
+
|
|
953
|
+
// WLAN SSID profiles and virtual-AP (most distinctive)
|
|
954
|
+
if (/^wlan\s+(ssid-profile|virtual-ap)\s+["']?[^"'\n]+["']?/m.test(sampleText)) {
|
|
955
|
+
return ArubaWLCSchema;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// AP groups (wireless controller specific)
|
|
959
|
+
if (/^ap-group\s+["']?[^"'\n]+["']?/m.test(sampleText)) {
|
|
960
|
+
return ArubaWLCSchema;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
// AAA authentication-server radius with quoted name (WLC style)
|
|
964
|
+
if (/^aaa\s+authentication-server\s+radius\s+["'][^"']+["']/m.test(sampleText)) {
|
|
965
|
+
return ArubaWLCSchema;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// RF profiles (ARM, dot11a, dot11g)
|
|
969
|
+
if (/^rf\s+(arm-profile|dot11[ag]-radio-profile)\s+["']?[^"'\n]+["']?/m.test(sampleText)) {
|
|
970
|
+
return ArubaWLCSchema;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
// AAA profile with quoted name (WLC style)
|
|
974
|
+
if (/^aaa\s+profile\s+["'][^"']+["']/m.test(sampleText)) {
|
|
975
|
+
return ArubaWLCSchema;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// ============ Aruba AOS-CX Detection ============
|
|
979
|
+
// AOS-CX uses Cisco-like syntax but with distinctive patterns
|
|
980
|
+
|
|
981
|
+
// AOS-CX version string
|
|
982
|
+
if (/^!Version\s+ArubaOS-CX/m.test(sampleText)) {
|
|
983
|
+
return ArubaAOSCXSchema;
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
// AOS-CX interface naming: slot/member/port format (1/1/1)
|
|
987
|
+
if (/^interface\s+\d+\/\d+\/\d+/m.test(sampleText)) {
|
|
988
|
+
return ArubaAOSCXSchema;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
// AOS-CX specific VLAN commands under interface
|
|
992
|
+
if (/^\s+vlan\s+(access|trunk\s+(native|allowed))\s+\d+/m.test(sampleText)) {
|
|
993
|
+
return ArubaAOSCXSchema;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// AOS-CX LAG interface
|
|
997
|
+
if (/^interface\s+lag\s+\d+/m.test(sampleText)) {
|
|
998
|
+
return ArubaAOSCXSchema;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// AOS-CX VSX configuration
|
|
1002
|
+
if (/^vsx\s*$/m.test(sampleText) || /^vsx-sync\s+/m.test(sampleText)) {
|
|
1003
|
+
return ArubaAOSCXSchema;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
// ============ Aruba AOS-Switch Detection ============
|
|
1007
|
+
// AOS-Switch (ProVision) uses VLAN-centric configuration
|
|
1008
|
+
|
|
1009
|
+
// ProCurve/ProVision configuration editor header
|
|
1010
|
+
if (/^;\s*[A-Z]\d+\w+\s+Configuration\s+Editor/m.test(sampleText)) {
|
|
1011
|
+
return ArubaAOSSwitchSchema;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// AOS-Switch VLAN with tagged/untagged port lists
|
|
1015
|
+
// Match either: vlan X\n tagged/untagged OR just indented tagged/untagged commands
|
|
1016
|
+
if (/^vlan\s+\d+[\s\S]*?^\s+(tagged|untagged)\s+[\dA-Za-z][\d,-]*/m.test(sampleText)) {
|
|
1017
|
+
return ArubaAOSSwitchSchema;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// Also detect if we see indented tagged/untagged patterns (AOS-Switch specific)
|
|
1021
|
+
if (/^\s+(tagged|untagged)\s+[\dA-Za-z,-]+\s*$/m.test(sampleText)) {
|
|
1022
|
+
return ArubaAOSSwitchSchema;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
// AOS-Switch hostname with ProCurve or Aruba prefix
|
|
1026
|
+
if (/^hostname\s+["']?(ProCurve|Aruba)/m.test(sampleText)) {
|
|
1027
|
+
return ArubaAOSSwitchSchema;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// AOS-Switch specific: trunk command for LAG (not Cisco trunk)
|
|
1031
|
+
// Distinguished by port numbers following trunk name
|
|
1032
|
+
if (/^trunk\s+[\dA-Za-z][\d,-]+\s+\w+/m.test(sampleText)) {
|
|
1033
|
+
return ArubaAOSSwitchSchema;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
// AOS-Switch specific: timesync sntp
|
|
1037
|
+
if (/^timesync\s+sntp/m.test(sampleText)) {
|
|
1038
|
+
return ArubaAOSSwitchSchema;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// ============ Cisco NX-OS Detection ============
|
|
1042
|
+
// NX-OS has feature activation commands and VDC support
|
|
1043
|
+
|
|
1044
|
+
// Feature commands at the start of config
|
|
1045
|
+
if (/^feature\s+\w+/m.test(sampleText)) {
|
|
1046
|
+
return CiscoNXOSSchema;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// NX-OS specific: VDC (Virtual Device Context)
|
|
1050
|
+
if (/^vdc\s+\w+/m.test(sampleText)) {
|
|
1051
|
+
return CiscoNXOSSchema;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// Install feature-set (NX-OS)
|
|
1055
|
+
if (/^install\s+feature-set/m.test(sampleText)) {
|
|
1056
|
+
return CiscoNXOSSchema;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// NX-OS specific: vrf context (vs IOS: ip vrf or vrf definition)
|
|
1060
|
+
if (/^vrf\s+context\s+\S+/m.test(sampleText)) {
|
|
1061
|
+
return CiscoNXOSSchema;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
// NX-OS specific: vpc domain
|
|
1065
|
+
if (/^vpc\s+domain\s+\d+/m.test(sampleText)) {
|
|
1066
|
+
return CiscoNXOSSchema;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
// ============ Arista EOS Detection ============
|
|
1070
|
+
// EOS is similar to IOS but has unique patterns
|
|
1071
|
+
|
|
1072
|
+
// MLAG configuration (most distinctive Arista feature)
|
|
1073
|
+
if (/^mlag\s+configuration/m.test(sampleText)) {
|
|
1074
|
+
return AristaEOSSchema;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// Management API (eAPI) - Arista specific
|
|
1078
|
+
if (/^management\s+api\s+(http-commands|gnmi|netconf|restconf)/m.test(sampleText)) {
|
|
1079
|
+
return AristaEOSSchema;
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// Arista daemon configuration
|
|
1083
|
+
if (/^daemon\s+\S+/m.test(sampleText)) {
|
|
1084
|
+
return AristaEOSSchema;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// Arista event-handler
|
|
1088
|
+
if (/^event-handler\s+\S+/m.test(sampleText)) {
|
|
1089
|
+
return AristaEOSSchema;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// CVX (CloudVision Exchange) - Arista specific
|
|
1093
|
+
if (/^cvx$/m.test(sampleText) || /^management\s+cvx/m.test(sampleText)) {
|
|
1094
|
+
return AristaEOSSchema;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
// Arista VRF instance syntax (vs Cisco vrf definition or vrf context)
|
|
1098
|
+
if (/^vrf\s+instance\s+\S+/m.test(sampleText)) {
|
|
1099
|
+
return AristaEOSSchema;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
// Arista interface Vxlan (VXLAN VTEP interface)
|
|
1103
|
+
if (/^interface\s+Vxlan\d*/m.test(sampleText)) {
|
|
1104
|
+
return AristaEOSSchema;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
// Arista-style VXLAN flood vtep
|
|
1108
|
+
if (/^\s+vxlan\s+(vni|flood\s+vtep|source-interface)/m.test(sampleText)) {
|
|
1109
|
+
return AristaEOSSchema;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
// Arista peer-filter (BGP)
|
|
1113
|
+
if (/^peer-filter\s+\S+/m.test(sampleText)) {
|
|
1114
|
+
return AristaEOSSchema;
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
// Arista tap aggregation
|
|
1118
|
+
if (/^tap\s+aggregation/m.test(sampleText)) {
|
|
1119
|
+
return AristaEOSSchema;
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
// Arista queue-monitor
|
|
1123
|
+
if (/^queue-monitor\s+(streaming|length)/m.test(sampleText)) {
|
|
1124
|
+
return AristaEOSSchema;
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// Arista traffic-policy
|
|
1128
|
+
if (/^traffic-policy\s+\S+/m.test(sampleText)) {
|
|
1129
|
+
return AristaEOSSchema;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
// Arista hardware counter feature
|
|
1133
|
+
if (/^hardware\s+counter\s+feature/m.test(sampleText)) {
|
|
1134
|
+
return AristaEOSSchema;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// Arista version string in show commands output or config
|
|
1138
|
+
if (/Arista\s+(DCS|vEOS|CCS)/m.test(sampleText)) {
|
|
1139
|
+
return AristaEOSSchema;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// Arista EOS software version format
|
|
1143
|
+
if (/^!\s*Software\s+image\s+version:\s+\d+\.\d+\.\d+/m.test(sampleText)) {
|
|
1144
|
+
return AristaEOSSchema;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// ============ Extreme Networks EXOS Detection ============
|
|
1148
|
+
// ExtremeXOS uses distinctive create/configure/enable command patterns
|
|
1149
|
+
// Must be checked before Cisco IOS as some patterns overlap
|
|
1150
|
+
|
|
1151
|
+
// EXOS distinctive "create vlan" command with named VLANs
|
|
1152
|
+
if (/^create\s+vlan\s+["']?\w+["']?\s*(tag\s+\d+)?/m.test(sampleText)) {
|
|
1153
|
+
return ExtremeEXOSSchema;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
// EXOS "configure vlan" commands (distinctive because VLANs are named)
|
|
1157
|
+
if (/^configure\s+vlan\s+["']?\w+["']?\s+(ipaddress|add\s+ports|tag)/m.test(sampleText)) {
|
|
1158
|
+
return ExtremeEXOSSchema;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
// EXOS SNMP sysname configuration (distinctive from Cisco hostname)
|
|
1162
|
+
if (/^configure\s+snmp\s+sysname\s+/m.test(sampleText)) {
|
|
1163
|
+
return ExtremeEXOSSchema;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
// EXOS "enable sharing" for LAG (EXOS-specific syntax)
|
|
1167
|
+
if (/^enable\s+sharing\s+\d+:\d+\s+grouping\s+/m.test(sampleText)) {
|
|
1168
|
+
return ExtremeEXOSSchema;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// EXOS "create eaps" for Ethernet Automatic Protection Switching
|
|
1172
|
+
if (/^create\s+eaps\s+\S+/m.test(sampleText)) {
|
|
1173
|
+
return ExtremeEXOSSchema;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// EXOS "configure sntp-client" (vs Cisco ntp server)
|
|
1177
|
+
if (/^configure\s+sntp-client\s+/m.test(sampleText)) {
|
|
1178
|
+
return ExtremeEXOSSchema;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// EXOS "enable sntp-client" (distinctive EXOS enable pattern)
|
|
1182
|
+
if (/^enable\s+sntp-client/m.test(sampleText)) {
|
|
1183
|
+
return ExtremeEXOSSchema;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// EXOS port format: slot:port (1:1, 2:24, etc.)
|
|
1187
|
+
// Combined with EXOS-specific commands
|
|
1188
|
+
if (/^configure\s+ports?\s+\d+:\d+/m.test(sampleText)) {
|
|
1189
|
+
return ExtremeEXOSSchema;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// EXOS "enable jumbo-frame ports" (EXOS-specific)
|
|
1193
|
+
if (/^enable\s+jumbo-frame\s+ports\s+/m.test(sampleText)) {
|
|
1194
|
+
return ExtremeEXOSSchema;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// EXOS "configure ip-mtu" (vs Cisco mtu)
|
|
1198
|
+
if (/^configure\s+ip-mtu\s+\d+\s+vlan\s+/m.test(sampleText)) {
|
|
1199
|
+
return ExtremeEXOSSchema;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
// EXOS Virtual Router (VR) configuration
|
|
1203
|
+
if (/^(create|configure)\s+vr\s+\S+/m.test(sampleText)) {
|
|
1204
|
+
return ExtremeEXOSSchema;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// EXOS MLAG peer configuration
|
|
1208
|
+
if (/^(create|configure)\s+mlag\s+peer\s+/m.test(sampleText)) {
|
|
1209
|
+
return ExtremeEXOSSchema;
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
// EXOS stacking configuration
|
|
1213
|
+
if (/^enable\s+stacking$/m.test(sampleText) || /^configure\s+stacking\s+node-address/m.test(sampleText)) {
|
|
1214
|
+
return ExtremeEXOSSchema;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
// EXOS ELRP (Extreme Loop Recovery Protocol)
|
|
1218
|
+
if (/^enable\s+elrp-client/m.test(sampleText)) {
|
|
1219
|
+
return ExtremeEXOSSchema;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// EXOS distinctive "configure vlan Default delete ports"
|
|
1223
|
+
if (/^configure\s+vlan\s+Default\s+delete\s+ports/m.test(sampleText)) {
|
|
1224
|
+
return ExtremeEXOSSchema;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
// ============ Extreme Networks VOSS Detection ============
|
|
1228
|
+
// VOSS uses Cisco-like syntax but with distinctive VSP/Fabric Connect patterns
|
|
1229
|
+
|
|
1230
|
+
// VOSS "vlan create" command (vs EXOS "create vlan")
|
|
1231
|
+
if (/^vlan\s+create\s+\d+\s+type\s+(port-mstprstp|spbm-bvlan)/m.test(sampleText)) {
|
|
1232
|
+
return ExtremeVOSSSchema;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// VOSS "vlan members" command (distinctive VOSS syntax)
|
|
1236
|
+
if (/^vlan\s+members\s+\d+\s+\d+\/\d+/m.test(sampleText)) {
|
|
1237
|
+
return ExtremeVOSSSchema;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
// VOSS "vlan i-sid" command (I-SID for SPBM/Fabric Connect)
|
|
1241
|
+
if (/^vlan\s+i-sid\s+\d+\s+\d+/m.test(sampleText)) {
|
|
1242
|
+
return ExtremeVOSSSchema;
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// VOSS "router isis" with SPBM configuration
|
|
1246
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
1247
|
+
if (hasVossRouterIsisSpbm(lines)) {
|
|
1248
|
+
return ExtremeVOSSSchema;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
// VOSS "spbm" command (Shortest Path Bridging MAC)
|
|
1252
|
+
if (/^spbm\s+\d+\s+(b-vid|nick-name|sys-id)/m.test(sampleText)) {
|
|
1253
|
+
return ExtremeVOSSSchema;
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
// VOSS "i-sid" command (Instance Service ID)
|
|
1257
|
+
if (/^i-sid\s+\d+\s+(vlan|elan-transparent)/m.test(sampleText)) {
|
|
1258
|
+
return ExtremeVOSSSchema;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// VOSS "interface GigabitEthernet" with slot/port format
|
|
1262
|
+
if (/^interface\s+GigabitEthernet\s+\d+\/\d+$/m.test(sampleText)) {
|
|
1263
|
+
return ExtremeVOSSSchema;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
// VOSS "interface mlt" (Multi-Link Trunk)
|
|
1267
|
+
if (/^interface\s+mlt\s+\d+/m.test(sampleText)) {
|
|
1268
|
+
return ExtremeVOSSSchema;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
// VOSS "mlt" command for MLT configuration
|
|
1272
|
+
if (/^mlt\s+\d+\s+(enable|name|member)/m.test(sampleText)) {
|
|
1273
|
+
return ExtremeVOSSSchema;
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
// VOSS "lacp enable" under interface or MLT
|
|
1277
|
+
if (/^lacp\s+(enable|key|aggregation-wait-time)/m.test(sampleText)) {
|
|
1278
|
+
return ExtremeVOSSSchema;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
// VOSS "dvr" command (Distributed Virtual Routing)
|
|
1282
|
+
if (/^dvr\s+(leaf|controller|domain-id)/m.test(sampleText)) {
|
|
1283
|
+
return ExtremeVOSSSchema;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// VOSS "cfm" command (Connectivity Fault Management)
|
|
1287
|
+
if (/^cfm\s+(spbm\s+mip|spbm\s+level|enable)/m.test(sampleText)) {
|
|
1288
|
+
return ExtremeVOSSSchema;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
// VOSS "snmp-server name" (vs Cisco hostname)
|
|
1292
|
+
if (/^snmp-server\s+name\s+["']?\S+["']?/m.test(sampleText)) {
|
|
1293
|
+
return ExtremeVOSSSchema;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
// VOSS "boot config flags" command
|
|
1297
|
+
if (/^boot\s+config\s+flags\s+/m.test(sampleText)) {
|
|
1298
|
+
return ExtremeVOSSSchema;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
// VOSS "sys name" command
|
|
1302
|
+
if (/^sys\s+name\s+["']?\S+["']?/m.test(sampleText)) {
|
|
1303
|
+
return ExtremeVOSSSchema;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
// ============ Nokia SR OS Detection ============
|
|
1307
|
+
// SR OS uses hierarchical CLI with configure/router/system blocks
|
|
1308
|
+
// and distinctive port notation (slot/mda/port) and admin-state commands
|
|
1309
|
+
// Must be checked before Huawei and Cisco as some patterns overlap
|
|
1310
|
+
|
|
1311
|
+
// Nokia SR OS distinctive "configure" followed by "router" block structure
|
|
1312
|
+
if (/^configure$/m.test(sampleText) && /^\s+router\s+"?[^"]*"?\s*$/m.test(sampleText)) {
|
|
1313
|
+
return NokiaSROSSchema;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
// Nokia SR OS distinctive port notation with admin-state
|
|
1317
|
+
// Port format: port X/Y/Z (slot/mda/port)
|
|
1318
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
1319
|
+
if (hasNokiaPortAdminState(lines)) {
|
|
1320
|
+
return NokiaSROSSchema;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
// Nokia SR OS router with named interfaces using quotes
|
|
1324
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
1325
|
+
if (hasNokiaRouterInterfaceBlock(lines)) {
|
|
1326
|
+
return NokiaSROSSchema;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// Nokia SR OS system name configuration (system > name "...")
|
|
1330
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
1331
|
+
if (hasNokiaSystemNameBlock(lines)) {
|
|
1332
|
+
return NokiaSROSSchema;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// Nokia SR OS service types (vpls, vprn, epipe, ies)
|
|
1336
|
+
if (/^\s+(vpls|vprn|epipe|ies)\s+\d+\s+(name|customer)/m.test(sampleText)) {
|
|
1337
|
+
return NokiaSROSSchema;
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
// Nokia SR OS SAP (Service Access Point) configuration
|
|
1341
|
+
if (/^\s+sap\s+\d+\/\d+\/\d+:\d+/m.test(sampleText)) {
|
|
1342
|
+
return NokiaSROSSchema;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
// Nokia SR OS MPLS LSP configuration
|
|
1346
|
+
if (/^\s+lsp\s+"[^"]+"\s*$/m.test(sampleText)) {
|
|
1347
|
+
return NokiaSROSSchema;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
// Nokia SR OS echo command for comments
|
|
1351
|
+
if (/^echo\s+"[^"]*"$/m.test(sampleText)) {
|
|
1352
|
+
return NokiaSROSSchema;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
// Nokia SR OS admin-state enable/disable pattern (very distinctive)
|
|
1356
|
+
if (/^\s+admin-state\s+(enable|disable)/m.test(sampleText)) {
|
|
1357
|
+
return NokiaSROSSchema;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
// Nokia SR OS policy-options block
|
|
1361
|
+
if (/^policy-options$/m.test(sampleText) && /^\s+policy-statement\s+"[^"]+"/m.test(sampleText)) {
|
|
1362
|
+
return NokiaSROSSchema;
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
// Nokia SR OS filter configuration
|
|
1366
|
+
if (/^filter$/m.test(sampleText) && /^\s+ip-filter\s+\d+/m.test(sampleText)) {
|
|
1367
|
+
return NokiaSROSSchema;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// Nokia SR OS exit all pattern (distinctive from other vendors)
|
|
1371
|
+
if (/^exit\s+all$/m.test(sampleText)) {
|
|
1372
|
+
return NokiaSROSSchema;
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// Nokia SR OS card and MDA configuration
|
|
1376
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
1377
|
+
if (hasNokiaCardMdaBlock(lines)) {
|
|
1378
|
+
return NokiaSROSSchema;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
// Nokia SR OS log configuration
|
|
1382
|
+
if (/^log$/m.test(sampleText) && /^\s+(log-id|syslog|snmp-trap-group)\s+\d+/m.test(sampleText)) {
|
|
1383
|
+
return NokiaSROSSchema;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
// Nokia SR OS BGP with group and neighbor using quoted names
|
|
1387
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous [\s\S]*? regex
|
|
1388
|
+
if (hasNokiaBgpGroupBlock(lines)) {
|
|
1389
|
+
return NokiaSROSSchema;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
// ============ Huawei VRP Detection ============
|
|
1393
|
+
// VRP uses distinctive sysname, interface naming, and undo commands
|
|
1394
|
+
// Must be checked before Cisco IOS as some patterns overlap
|
|
1395
|
+
|
|
1396
|
+
// Huawei sysname command (most distinctive - vs Cisco's hostname)
|
|
1397
|
+
if (/^sysname\s+\S+/m.test(sampleText)) {
|
|
1398
|
+
return HuaweiVRPSchema;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// Huawei VRP version/header comment
|
|
1402
|
+
if (/^#\s*(HuaWei|huawei|Huawei)/m.test(sampleText)) {
|
|
1403
|
+
return HuaweiVRPSchema;
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
// Huawei interface naming: GigabitEthernet X/Y/Z format (slot/card/port)
|
|
1407
|
+
// Note: Must be before Cisco detection since Cisco also uses GigabitEthernet
|
|
1408
|
+
// Huawei uses space before numbers: "GigabitEthernet 0/0/1" vs Cisco "GigabitEthernet0/0/1"
|
|
1409
|
+
if (/^interface\s+GigabitEthernet\s+\d+\/\d+\/\d+/m.test(sampleText)) {
|
|
1410
|
+
return HuaweiVRPSchema;
|
|
1411
|
+
}
|
|
1412
|
+
|
|
1413
|
+
// Huawei high-speed interface naming: XGigabitEthernet, 40GE, 100GE
|
|
1414
|
+
if (/^interface\s+(XGigabitEthernet|40GE|100GE|25GE|10GE|Eth-Trunk)\s*/m.test(sampleText)) {
|
|
1415
|
+
return HuaweiVRPSchema;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
// Huawei Vlanif interface (vs Cisco's Vlan or interface Vlan)
|
|
1419
|
+
if (/^interface\s+Vlanif\s*\d+/m.test(sampleText)) {
|
|
1420
|
+
return HuaweiVRPSchema;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
// Huawei VRP undo command (negation - very distinctive)
|
|
1424
|
+
if (/^\s*undo\s+(info-center|shutdown|portswitch|stp|lldp|ntdp)/m.test(sampleText)) {
|
|
1425
|
+
return HuaweiVRPSchema;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// Huawei protocol configuration with process ID directly after keyword
|
|
1429
|
+
// ospf 1, bgp 65000, isis 1 (vs Cisco's router ospf 1, router bgp 65000)
|
|
1430
|
+
if (/^ospf\s+\d+\s*$/m.test(sampleText) || /^bgp\s+\d+\s*$/m.test(sampleText)) {
|
|
1431
|
+
return HuaweiVRPSchema;
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
// Huawei isis configuration
|
|
1435
|
+
if (/^isis\s+\d+\s*$/m.test(sampleText)) {
|
|
1436
|
+
return HuaweiVRPSchema;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
// Huawei AAA configuration block
|
|
1440
|
+
// SEC-002: Use safe line-by-line helper instead of dangerous combined regex
|
|
1441
|
+
if (hasHuaweiAaaBlock(lines)) {
|
|
1442
|
+
return HuaweiVRPSchema;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// Huawei user-interface configuration (vs Cisco's line vty)
|
|
1446
|
+
if (/^user-interface\s+(vty|console|current)\s*/m.test(sampleText)) {
|
|
1447
|
+
return HuaweiVRPSchema;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
// Huawei local-user configuration
|
|
1451
|
+
if (/^local-user\s+\S+\s+(password|privilege|service-type)/m.test(sampleText)) {
|
|
1452
|
+
return HuaweiVRPSchema;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// Huawei VPN instance (vs Cisco's ip vrf or vrf definition)
|
|
1456
|
+
if (/^ip\s+vpn-instance\s+\S+/m.test(sampleText)) {
|
|
1457
|
+
return HuaweiVRPSchema;
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
// Huawei HWTACACS (Huawei's TACACS implementation)
|
|
1461
|
+
if (/^hwtacacs-server\s+(template|shared-key)/m.test(sampleText)) {
|
|
1462
|
+
return HuaweiVRPSchema;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// Huawei info-center (logging configuration)
|
|
1466
|
+
if (/^info-center\s+(enable|source|loghost)/m.test(sampleText)) {
|
|
1467
|
+
return HuaweiVRPSchema;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
// Huawei drop-profile or queue-profile
|
|
1471
|
+
if (/^(drop-profile|qos\s+queue-profile)\s+\S+/m.test(sampleText)) {
|
|
1472
|
+
return HuaweiVRPSchema;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
// Huawei port link-type in interface context
|
|
1476
|
+
if (/^\s*port\s+link-type\s+(access|trunk|hybrid)/m.test(sampleText)) {
|
|
1477
|
+
return HuaweiVRPSchema;
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
// Huawei port default vlan (vs Cisco switchport access vlan)
|
|
1481
|
+
if (/^\s*port\s+default\s+vlan\s+\d+/m.test(sampleText)) {
|
|
1482
|
+
return HuaweiVRPSchema;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// Huawei port trunk allow-pass vlan
|
|
1486
|
+
if (/^\s*port\s+trunk\s+allow-pass\s+vlan\s+/m.test(sampleText)) {
|
|
1487
|
+
return HuaweiVRPSchema;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
// Huawei display commands in comments or header
|
|
1491
|
+
if (/^#\s*display\s+current-configuration/m.test(sampleText)) {
|
|
1492
|
+
return HuaweiVRPSchema;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
// Huawei return command (exits to user view)
|
|
1496
|
+
if (/^return\s*$/m.test(sampleText)) {
|
|
1497
|
+
return HuaweiVRPSchema;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
// ============ Default: Cisco IOS ============
|
|
1501
|
+
// Most common format, used as fallback
|
|
1502
|
+
return CiscoIOSSchema;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
// Re-export all vendor schemas for direct access
|
|
1506
|
+
export { CiscoIOSSchema } from './cisco-ios';
|
|
1507
|
+
export { CiscoNXOSSchema } from './cisco-nxos';
|
|
1508
|
+
export { JuniperJunOSSchema } from './juniper-junos';
|
|
1509
|
+
export { ArubaAOSCXSchema } from './aruba-aoscx';
|
|
1510
|
+
export { ArubaAOSSwitchSchema } from './aruba-aosswitch';
|
|
1511
|
+
export { ArubaWLCSchema } from './aruba-wlc';
|
|
1512
|
+
export { PaloAltoPANOSSchema } from './paloalto-panos';
|
|
1513
|
+
export { AristaEOSSchema } from './arista-eos';
|
|
1514
|
+
export { VyOSSchema } from './vyos-vyos';
|
|
1515
|
+
export { FortinetFortiGateSchema } from './fortinet-fortigate';
|
|
1516
|
+
export { ExtremeEXOSSchema } from './extreme-exos';
|
|
1517
|
+
export { ExtremeVOSSSchema } from './extreme-voss';
|
|
1518
|
+
export { HuaweiVRPSchema } from './huawei-vrp';
|
|
1519
|
+
export { MikroTikRouterOSSchema } from './mikrotik-routeros';
|
|
1520
|
+
export { NokiaSROSSchema } from './nokia-sros';
|
|
1521
|
+
export { CumulusLinuxSchema } from './cumulus-linux';
|