trigger 2.0.0__py3-none-any.whl
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.
- trigger/__init__.py +7 -0
- trigger/acl/__init__.py +32 -0
- trigger/acl/autoacl.py +70 -0
- trigger/acl/db.py +324 -0
- trigger/acl/dicts.py +357 -0
- trigger/acl/grammar.py +112 -0
- trigger/acl/ios.py +222 -0
- trigger/acl/junos.py +422 -0
- trigger/acl/models.py +118 -0
- trigger/acl/parser.py +168 -0
- trigger/acl/queue.py +296 -0
- trigger/acl/support.py +1431 -0
- trigger/acl/tools.py +746 -0
- trigger/bin/__init__.py +0 -0
- trigger/bin/acl.py +233 -0
- trigger/bin/acl_script.py +574 -0
- trigger/bin/aclconv.py +82 -0
- trigger/bin/check_access.py +93 -0
- trigger/bin/check_syntax.py +66 -0
- trigger/bin/fe.py +197 -0
- trigger/bin/find_access.py +191 -0
- trigger/bin/gnng.py +434 -0
- trigger/bin/gong.py +86 -0
- trigger/bin/load_acl.py +841 -0
- trigger/bin/load_config.py +18 -0
- trigger/bin/netdev.py +317 -0
- trigger/bin/optimizer.py +638 -0
- trigger/bin/run_cmds.py +18 -0
- trigger/changemgmt/__init__.py +352 -0
- trigger/changemgmt/bounce.py +57 -0
- trigger/cmds.py +1217 -0
- trigger/conf/__init__.py +94 -0
- trigger/conf/global_settings.py +674 -0
- trigger/contrib/__init__.py +7 -0
- trigger/exceptions.py +307 -0
- trigger/gorc.py +172 -0
- trigger/netdevices/__init__.py +1288 -0
- trigger/netdevices/loader.py +174 -0
- trigger/netscreen.py +1030 -0
- trigger/packages/__init__.py +6 -0
- trigger/packages/peewee.py +8084 -0
- trigger/rancid.py +463 -0
- trigger/tacacsrc.py +584 -0
- trigger/twister.py +2203 -0
- trigger/twister2.py +745 -0
- trigger/utils/__init__.py +88 -0
- trigger/utils/cli.py +349 -0
- trigger/utils/importlib.py +77 -0
- trigger/utils/network.py +157 -0
- trigger/utils/rcs.py +178 -0
- trigger/utils/templates.py +81 -0
- trigger/utils/url.py +78 -0
- trigger/utils/xmltodict.py +298 -0
- trigger-2.0.0.dist-info/METADATA +146 -0
- trigger-2.0.0.dist-info/RECORD +61 -0
- trigger-2.0.0.dist-info/WHEEL +5 -0
- trigger-2.0.0.dist-info/entry_points.txt +15 -0
- trigger-2.0.0.dist-info/licenses/AUTHORS.md +20 -0
- trigger-2.0.0.dist-info/licenses/LICENSE.md +28 -0
- trigger-2.0.0.dist-info/top_level.txt +2 -0
- twisted/plugins/trigger_xmlrpc.py +124 -0
trigger/acl/dicts.py
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This code is originally from parser.py. It contains all the simple data definitions in
|
|
3
|
+
form of dictionaries and lists and such. This file is not meant to by used by itself.
|
|
4
|
+
Imported into support.py.
|
|
5
|
+
|
|
6
|
+
Variables defined:
|
|
7
|
+
|
|
8
|
+
adrsbk
|
|
9
|
+
dscp_names
|
|
10
|
+
fragment_flag_names
|
|
11
|
+
icmp_reject_codes
|
|
12
|
+
icmp_types
|
|
13
|
+
icmp_codes
|
|
14
|
+
ip_option_names
|
|
15
|
+
ios_icmp_messages
|
|
16
|
+
ios_icmp_names
|
|
17
|
+
junos_match_ordering_list
|
|
18
|
+
junos_match_order
|
|
19
|
+
address_matches
|
|
20
|
+
ports
|
|
21
|
+
precedence_names
|
|
22
|
+
tcp_flag_names
|
|
23
|
+
tcp_flag_specials
|
|
24
|
+
tcp_flag_rev
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
__author__ = "Jathan McCollum, Mike Biancaniello, Michael Harding, Michael Shields"
|
|
28
|
+
__editor__ = "Joseph Malone"
|
|
29
|
+
__maintainer__ = "Jathan McCollum"
|
|
30
|
+
__email__ = "jathanism@aol.com"
|
|
31
|
+
__copyright__ = "Copyright 2006-2013, AOL Inc.; 2013 Saleforce.com"
|
|
32
|
+
|
|
33
|
+
adrsbk = {"svc": {"group": {}, "book": {}}, "addr": {"group": {}, "book": {}}}
|
|
34
|
+
|
|
35
|
+
dscp_names = {
|
|
36
|
+
"be": 0,
|
|
37
|
+
"cs0": 0,
|
|
38
|
+
"cs1": 8,
|
|
39
|
+
"af11": 10,
|
|
40
|
+
"af12": 12,
|
|
41
|
+
"af13": 14,
|
|
42
|
+
"cs2": 16,
|
|
43
|
+
"af21": 18,
|
|
44
|
+
"af22": 20,
|
|
45
|
+
"af23": 22,
|
|
46
|
+
"cs3": 24,
|
|
47
|
+
"af31": 26,
|
|
48
|
+
"af32": 28,
|
|
49
|
+
"af33": 30,
|
|
50
|
+
"cs4": 32,
|
|
51
|
+
"af41": 34,
|
|
52
|
+
"af42": 36,
|
|
53
|
+
"af43": 38,
|
|
54
|
+
"cs5": 40,
|
|
55
|
+
"ef": 46,
|
|
56
|
+
"cs6": 48,
|
|
57
|
+
"cs7": 56,
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
fragment_flag_names = {
|
|
61
|
+
"dont-fragment": 0x4000,
|
|
62
|
+
"more-fragments": 0x2000,
|
|
63
|
+
"reserved": 0x8000,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
icmp_reject_codes = (
|
|
67
|
+
"administratively-prohibited",
|
|
68
|
+
"bad-host-tos",
|
|
69
|
+
"bad-network-tos",
|
|
70
|
+
"host-prohibited",
|
|
71
|
+
"host-unknown",
|
|
72
|
+
"host-unreachable",
|
|
73
|
+
"network-prohibited",
|
|
74
|
+
"network-unknown",
|
|
75
|
+
"network-unreachable",
|
|
76
|
+
"port-unreachable",
|
|
77
|
+
"precedence-cutoff",
|
|
78
|
+
"precedence-violation",
|
|
79
|
+
"protocol-unreachable",
|
|
80
|
+
"source-host-isolated",
|
|
81
|
+
"source-route-failed",
|
|
82
|
+
"tcp-reset",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
icmp_types = {
|
|
86
|
+
"echo-reply": 0,
|
|
87
|
+
"echo-request": 8,
|
|
88
|
+
"echo": 8, # undocumented
|
|
89
|
+
"info-reply": 16,
|
|
90
|
+
"info-request": 15,
|
|
91
|
+
"information-reply": 16,
|
|
92
|
+
"information-request": 15,
|
|
93
|
+
"mask-request": 17,
|
|
94
|
+
"mask-reply": 18,
|
|
95
|
+
"parameter-problem": 12,
|
|
96
|
+
"redirect": 5,
|
|
97
|
+
"router-advertisement": 9,
|
|
98
|
+
"router-solicit": 10,
|
|
99
|
+
"source-quench": 4,
|
|
100
|
+
"time-exceeded": 11,
|
|
101
|
+
"timestamp": 13,
|
|
102
|
+
"timestamp-reply": 14,
|
|
103
|
+
"unreachable": 3,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
icmp_codes = {
|
|
107
|
+
"ip-header-bad": 0,
|
|
108
|
+
"required-option-missing": 1,
|
|
109
|
+
"redirect-for-host": 1,
|
|
110
|
+
"redirect-for-network": 0,
|
|
111
|
+
"redirect-for-tos-and-host": 3,
|
|
112
|
+
"redirect-for-tos-and-net": 2,
|
|
113
|
+
"ttl-eq-zero-during-reassembly": 1,
|
|
114
|
+
"ttl-eq-zero-during-transit": 0,
|
|
115
|
+
"communication-prohibited-by-filtering": 13,
|
|
116
|
+
"destination-host-prohibited": 10,
|
|
117
|
+
"destination-host-unknown": 7,
|
|
118
|
+
"destination-network-prohibited": 9,
|
|
119
|
+
"destination-network-unknown": 6,
|
|
120
|
+
"fragmentation-needed": 4,
|
|
121
|
+
"host-precedence-violation": 14,
|
|
122
|
+
"host-unreachable": 1,
|
|
123
|
+
"host-unreachable-for-TOS": 12,
|
|
124
|
+
"network-unreachable": 0,
|
|
125
|
+
"network-unreachable-for-TOS": 11,
|
|
126
|
+
"port-unreachable": 3,
|
|
127
|
+
"precedence-cutoff-in-effect": 15,
|
|
128
|
+
"protocol-unreachable": 2,
|
|
129
|
+
"source-host-isolated": 8,
|
|
130
|
+
"source-route-failed": 5,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
ip_option_names = {
|
|
134
|
+
"loose-source-route": 131,
|
|
135
|
+
"record-route": 7,
|
|
136
|
+
"router-alert": 148,
|
|
137
|
+
"strict-source-route": 137,
|
|
138
|
+
"timestamp": 68,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Cisco "ICMP message type names and ICMP message type and code names" from
|
|
142
|
+
# IOS 12.0 documentation. Verified these against actual practice of 12.1(21),
|
|
143
|
+
# since documentation is incomplete. For example, is 'echo' code 8, type 0
|
|
144
|
+
# or code 8, type any? Experiment shows that it is code 8, type any.
|
|
145
|
+
ios_icmp_messages = {
|
|
146
|
+
"administratively-prohibited": (3, 13),
|
|
147
|
+
"alternate-address": (6,),
|
|
148
|
+
"conversion-error": (31,),
|
|
149
|
+
"dod-host-prohibited": (3, 10),
|
|
150
|
+
"dod-net-prohibited": (3, 9),
|
|
151
|
+
"echo": (8,),
|
|
152
|
+
"echo-reply": (0,),
|
|
153
|
+
"general-parameter-problem": (12, 0),
|
|
154
|
+
"host-isolated": (3, 8),
|
|
155
|
+
"host-precedence-unreachable": (3, 14),
|
|
156
|
+
"host-redirect": (5, 1),
|
|
157
|
+
"host-tos-redirect": (5, 3),
|
|
158
|
+
"host-tos-unreachable": (3, 12),
|
|
159
|
+
"host-unknown": (3, 7),
|
|
160
|
+
"host-unreachable": (3, 1),
|
|
161
|
+
"information-reply": (16,),
|
|
162
|
+
"information-request": (15,),
|
|
163
|
+
"mask-reply": (18,),
|
|
164
|
+
"mask-request": (17,),
|
|
165
|
+
"mobile-redirect": (32,),
|
|
166
|
+
"net-redirect": (5, 0),
|
|
167
|
+
"net-tos-redirect": (5, 2),
|
|
168
|
+
"net-tos-unreachable": (3, 11),
|
|
169
|
+
"net-unreachable": (3, 0),
|
|
170
|
+
"network-unknown": (3, 6),
|
|
171
|
+
"no-room-for-option": (12, 2),
|
|
172
|
+
"option-missing": (12, 1),
|
|
173
|
+
"packet-too-big": (3, 4),
|
|
174
|
+
"parameter-problem": (12,),
|
|
175
|
+
"port-unreachable": (3, 3),
|
|
176
|
+
"precedence-unreachable": (3, 14), # not (3, 15)
|
|
177
|
+
"protocol-unreachable": (3, 2),
|
|
178
|
+
"reassembly-timeout": (11, 1), # not (11, 2)
|
|
179
|
+
"redirect": (5,),
|
|
180
|
+
"router-advertisement": (9,),
|
|
181
|
+
"router-solicitation": (10,),
|
|
182
|
+
"source-quench": (4,),
|
|
183
|
+
"source-route-failed": (3, 5),
|
|
184
|
+
"time-exceeded": (11,),
|
|
185
|
+
"timestamp-reply": (14,),
|
|
186
|
+
"timestamp-request": (13,),
|
|
187
|
+
"traceroute": (30,),
|
|
188
|
+
"ttl-exceeded": (11, 0),
|
|
189
|
+
"unreachable": (3,),
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
ios_icmp_names = {v: k for k, v in ios_icmp_messages.items()}
|
|
193
|
+
|
|
194
|
+
# Ordering for JunOS match clauses. AOL style rules:
|
|
195
|
+
# 1. Use the order found in the IP header, except, put protocol at the end
|
|
196
|
+
# so it is close to the port and tcp-flags.
|
|
197
|
+
# 2. General before specific.
|
|
198
|
+
# 3. Source before destination.
|
|
199
|
+
junos_match_ordering_list = (
|
|
200
|
+
"source-mac-address",
|
|
201
|
+
"destination-mac-address",
|
|
202
|
+
"packet-length",
|
|
203
|
+
"fragment-flags",
|
|
204
|
+
"fragment-offset",
|
|
205
|
+
"first-fragment",
|
|
206
|
+
"is-fragment",
|
|
207
|
+
"prefix-list",
|
|
208
|
+
"address",
|
|
209
|
+
"source-prefix-list",
|
|
210
|
+
"source-address",
|
|
211
|
+
"destination-prefix-list",
|
|
212
|
+
"destination-address",
|
|
213
|
+
"ip-options",
|
|
214
|
+
"protocol",
|
|
215
|
+
# TCP/UDP
|
|
216
|
+
"tcp-flags",
|
|
217
|
+
"port",
|
|
218
|
+
"source-port",
|
|
219
|
+
"destination-port",
|
|
220
|
+
# ICMP
|
|
221
|
+
"icmp-code",
|
|
222
|
+
"icmp-type",
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
junos_match_order = {}
|
|
226
|
+
|
|
227
|
+
for i, match in enumerate(junos_match_ordering_list):
|
|
228
|
+
junos_match_order[match] = i * 2
|
|
229
|
+
junos_match_order[match + "-except"] = i * 2 + 1
|
|
230
|
+
|
|
231
|
+
# These types of Juniper matches go in braces, not square brackets.
|
|
232
|
+
address_matches = {
|
|
233
|
+
"address",
|
|
234
|
+
"destination-address",
|
|
235
|
+
"source-address",
|
|
236
|
+
"prefix-list",
|
|
237
|
+
"source-prefix-list",
|
|
238
|
+
"destination-prefix-list",
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
for match in list(address_matches):
|
|
242
|
+
address_matches.add(match + "-except")
|
|
243
|
+
|
|
244
|
+
# Not all of these are in /etc/services even as of RHEL 4; for example, it
|
|
245
|
+
# has 'syslog' only in UDP, and 'dns' as 'domain'. Also, Cisco (according
|
|
246
|
+
# to the IOS 12.0 documentation at least) allows 'dns' in UDP and not TCP,
|
|
247
|
+
# along with other anomalies. We'll be somewhat more generous in parsing
|
|
248
|
+
# input, and always output as integers.
|
|
249
|
+
ports = {
|
|
250
|
+
"afs": 1483, # JunOS
|
|
251
|
+
"bgp": 179,
|
|
252
|
+
"biff": 512,
|
|
253
|
+
"bootpc": 68,
|
|
254
|
+
"bootps": 67,
|
|
255
|
+
"chargen": 19,
|
|
256
|
+
"cmd": 514, # undocumented IOS
|
|
257
|
+
"cvspserver": 2401, # JunOS
|
|
258
|
+
"daytime": 13,
|
|
259
|
+
"dhcp": 67, # JunOS
|
|
260
|
+
"discard": 9,
|
|
261
|
+
"dns": 53,
|
|
262
|
+
"dnsix": 90,
|
|
263
|
+
"domain": 53,
|
|
264
|
+
"echo": 7,
|
|
265
|
+
"eklogin": 2105, # JunOS
|
|
266
|
+
"ekshell": 2106, # JunOS
|
|
267
|
+
"exec": 512, # undocumented IOS
|
|
268
|
+
"finger": 79,
|
|
269
|
+
"ftp": 21,
|
|
270
|
+
"ftp-data": 20,
|
|
271
|
+
"gopher": 70,
|
|
272
|
+
"hostname": 101,
|
|
273
|
+
"http": 80, # JunOS
|
|
274
|
+
"https": 443, # JunOS
|
|
275
|
+
"ident": 113, # undocumented IOS
|
|
276
|
+
"imap": 143, # JunOS
|
|
277
|
+
"irc": 194,
|
|
278
|
+
"isakmp": 500, # undocumented IOS
|
|
279
|
+
"kerberos-sec": 88, # JunOS
|
|
280
|
+
"klogin": 543,
|
|
281
|
+
"kpasswd": 761, # JunOS
|
|
282
|
+
"kshell": 544,
|
|
283
|
+
"ldap": 389, # JunOS
|
|
284
|
+
"ldp": 646, # undocumented JunOS
|
|
285
|
+
"login": 513, # JunOS
|
|
286
|
+
"lpd": 515,
|
|
287
|
+
"mobile-ip": 434,
|
|
288
|
+
"mobileip-agent": 434, # JunOS
|
|
289
|
+
"mobileip-mn": 435, # JunOS
|
|
290
|
+
"msdp": 639, # JunOS
|
|
291
|
+
"nameserver": 42,
|
|
292
|
+
"netbios-dgm": 138,
|
|
293
|
+
"netbios-ns": 137,
|
|
294
|
+
"netbios-ssn": 139, # JunOS
|
|
295
|
+
"nfsd": 2049, # JunOS
|
|
296
|
+
"nntp": 119,
|
|
297
|
+
"ntalk": 518, # JunOS
|
|
298
|
+
"ntp": 123,
|
|
299
|
+
"pop2": 109,
|
|
300
|
+
"pop3": 110,
|
|
301
|
+
"pptp": 1723, # JunOS
|
|
302
|
+
"printer": 515, # JunOS
|
|
303
|
+
"radacct": 1813, # JunOS
|
|
304
|
+
"radius": 1812, # JunOS and undocumented IOS
|
|
305
|
+
"rip": 520,
|
|
306
|
+
"rkinit": 2108, # JunOS
|
|
307
|
+
"smtp": 25,
|
|
308
|
+
"snmp": 161,
|
|
309
|
+
"snmptrap": 162,
|
|
310
|
+
"snmp-trap": 162, # undocumented IOS
|
|
311
|
+
"snpp": 444, # JunOS
|
|
312
|
+
"socks": 1080, # JunOS
|
|
313
|
+
"ssh": 22, # JunOS
|
|
314
|
+
"sunrpc": 111,
|
|
315
|
+
"syslog": 514,
|
|
316
|
+
"tacacs": 49, # undocumented IOS
|
|
317
|
+
"tacacs-ds": 49,
|
|
318
|
+
"talk": 517,
|
|
319
|
+
"telnet": 23,
|
|
320
|
+
"tftp": 69,
|
|
321
|
+
"time": 37,
|
|
322
|
+
"timed": 525, # JunOS
|
|
323
|
+
"uucp": 540,
|
|
324
|
+
"who": 513,
|
|
325
|
+
"whois": 43,
|
|
326
|
+
"www": 80,
|
|
327
|
+
"xdmcp": 177,
|
|
328
|
+
"zephyr-clt": 2103, # JunOS
|
|
329
|
+
"zephyr-hm": 2104, # JunOS
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
precedence_names = {
|
|
333
|
+
"critical-ecp": 0xA0, # JunOS
|
|
334
|
+
"critical": 0xA0, # IOS
|
|
335
|
+
"flash": 0x60,
|
|
336
|
+
"flash-override": 0x80,
|
|
337
|
+
"immediate": 0x40,
|
|
338
|
+
"internet-control": 0xC0, # JunOS
|
|
339
|
+
"internet": 0xC0, # IOS
|
|
340
|
+
"net-control": 0xE0, # JunOS
|
|
341
|
+
"network": 0xE0, # IOS
|
|
342
|
+
"priority": 0x20,
|
|
343
|
+
"routine": 0x00,
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
tcp_flag_names = {
|
|
347
|
+
"ack": 0x10,
|
|
348
|
+
"fin": 0x01,
|
|
349
|
+
"push": 0x08,
|
|
350
|
+
"rst": 0x04,
|
|
351
|
+
"syn": 0x02,
|
|
352
|
+
"urgent": 0x20,
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
tcp_flag_specials = {"tcp-established": '"ack | rst"', "tcp-initial": '"syn & !ack"'}
|
|
356
|
+
|
|
357
|
+
tcp_flag_rev = {v: k for k, v in tcp_flag_specials.items()}
|
trigger/acl/grammar.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This code is originally from parser.py. This is the basic grammar and rules
|
|
3
|
+
from which the other specific grammars are built. This file is not meant to by used by itself.
|
|
4
|
+
Imported into the specific grammar files.
|
|
5
|
+
|
|
6
|
+
#Constants
|
|
7
|
+
errs
|
|
8
|
+
rules
|
|
9
|
+
#Functions
|
|
10
|
+
S
|
|
11
|
+
literals
|
|
12
|
+
update
|
|
13
|
+
dict_sum
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
__author__ = "Jathan McCollum, Mike Biancaniello, Michael Harding, Michael Shields"
|
|
17
|
+
__editor__ = "Joseph Malone"
|
|
18
|
+
__maintainer__ = "Jathan McCollum"
|
|
19
|
+
__email__ = "jathanism@aol.com"
|
|
20
|
+
__copyright__ = "Copyright 2006-2013, AOL Inc.; 2013 Saleforce.com"
|
|
21
|
+
|
|
22
|
+
from .support import *
|
|
23
|
+
|
|
24
|
+
# Each production can be any of:
|
|
25
|
+
# 1. string
|
|
26
|
+
# if no subtags: -> matched text
|
|
27
|
+
# if single subtag: -> value of that
|
|
28
|
+
# if list: -> list of the value of each tag
|
|
29
|
+
# 2. (string, object) -> object
|
|
30
|
+
# 3. (string, callable_object) -> object(arg)
|
|
31
|
+
|
|
32
|
+
subtagged = set()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def S(prod):
|
|
36
|
+
"""
|
|
37
|
+
Wrap your grammar token in this to call your helper function with a list
|
|
38
|
+
of each parsed subtag, instead of the raw text. This is useful for
|
|
39
|
+
performing modifiers.
|
|
40
|
+
|
|
41
|
+
:param prod: The parser product.
|
|
42
|
+
"""
|
|
43
|
+
subtagged.add(prod)
|
|
44
|
+
return prod
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def literals(d):
|
|
48
|
+
"""Longest match of all the strings that are keys of 'd'."""
|
|
49
|
+
keys = [str(key) for key in d]
|
|
50
|
+
keys.sort(key=lambda x: -len(x)) # Sort by length descending
|
|
51
|
+
return " / ".join(['"%s"' % key for key in keys])
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def update(d, **kwargs):
|
|
55
|
+
# Check for duplicate subterms, which is legal but too confusing to be
|
|
56
|
+
# allowed at AOL. For example, a Juniper term can have two different
|
|
57
|
+
# 'destination-address' clauses, which means that the first will be
|
|
58
|
+
# ignored. This led to an outage on 2006-10-11.
|
|
59
|
+
for key in kwargs.keys():
|
|
60
|
+
if key in d:
|
|
61
|
+
raise exceptions.ParseError("duplicate %s" % key)
|
|
62
|
+
d.update(kwargs)
|
|
63
|
+
return d
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def dict_sum(dlist):
|
|
67
|
+
dsum = {}
|
|
68
|
+
for d in dlist:
|
|
69
|
+
for k, v in d.items():
|
|
70
|
+
if k in dsum:
|
|
71
|
+
dsum[k] += v
|
|
72
|
+
else:
|
|
73
|
+
dsum[k] = v
|
|
74
|
+
return dsum
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
## syntax error messages
|
|
78
|
+
errs = {
|
|
79
|
+
"comm_start": '"comment missing /* below line %(line)s"',
|
|
80
|
+
"comm_stop": '"comment missing */ below line %(line)s"',
|
|
81
|
+
"default": '"expected %(expected)s line %(line)s"',
|
|
82
|
+
"semicolon": '"missing semicolon on line %(line)s"',
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
rules = {
|
|
86
|
+
"digits": "[0-9]+",
|
|
87
|
+
"<digits_s>": "[0-9]+",
|
|
88
|
+
"<ts>": "[ \\t]+",
|
|
89
|
+
"<ws>": "[ \\t\\n]+",
|
|
90
|
+
"<EOL>": "('\r'?,'\n')/EOF",
|
|
91
|
+
"alphanums": "[a-zA-Z0-9]+",
|
|
92
|
+
"word": "[a-zA-Z0-9_.-]+",
|
|
93
|
+
"anychar": "[ a-zA-Z0-9.$:()&,/'_-]",
|
|
94
|
+
"hex": "[0-9a-fA-F]+",
|
|
95
|
+
"ipchars": "[0-9a-fA-F:.]+",
|
|
96
|
+
"ipv4": ('digits, (".", digits)*', TIP),
|
|
97
|
+
"ipaddr": ("ipchars", TIP),
|
|
98
|
+
"cidr": (
|
|
99
|
+
'("inactive:", ws+)?, (ipaddr / ipv4), "/", digits, (ws+, "except")?',
|
|
100
|
+
TIP,
|
|
101
|
+
),
|
|
102
|
+
"macaddr": 'hex, (":", hex)+',
|
|
103
|
+
"protocol": (literals(Protocol.name2num) + " / digits", do_protocol_lookup),
|
|
104
|
+
"tcp": ('"tcp" / "6"', Protocol("tcp")),
|
|
105
|
+
"udp": ('"udp" / "17"', Protocol("udp")),
|
|
106
|
+
"icmp": ('"icmp" / "1"', Protocol("icmp")),
|
|
107
|
+
"icmp_type": (literals(icmp_types) + " / digits", do_icmp_type_lookup),
|
|
108
|
+
"icmp_code": (literals(icmp_codes) + " / digits", do_icmp_code_lookup),
|
|
109
|
+
"port": (literals(ports) + " / digits", do_port_lookup),
|
|
110
|
+
"dscp": (literals(dscp_names) + " / digits", do_dscp_lookup),
|
|
111
|
+
"root": "ws?, junos_raw_acl / junos_replace_family_acl / junos_replace_acl / junos_replace_policers / ios_acl, ws?",
|
|
112
|
+
}
|
trigger/acl/ios.py
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This code is originally from parser.py. This file is not meant to by used by itself.
|
|
3
|
+
This is for IOS like ACLs
|
|
4
|
+
|
|
5
|
+
#Constants
|
|
6
|
+
unary_port_operators
|
|
7
|
+
rules - this is really from the grammar.py
|
|
8
|
+
# Classes
|
|
9
|
+
'Remark',
|
|
10
|
+
# Functions
|
|
11
|
+
'handle_ios_match',
|
|
12
|
+
'handle_ios_acl',
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
# Copied metadata from parser.py
|
|
16
|
+
__author__ = "Jathan McCollum, Mike Biancaniello, Michael Harding, Michael Shields"
|
|
17
|
+
__editor__ = "Joseph Malone"
|
|
18
|
+
__maintainer__ = "Jathan McCollum"
|
|
19
|
+
__email__ = "jathanism@aol.com"
|
|
20
|
+
__copyright__ = "Copyright 2006-2013, AOL Inc.; 2013 Saleforce.com"
|
|
21
|
+
|
|
22
|
+
from .grammar import *
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Remark(Comment):
|
|
26
|
+
"""
|
|
27
|
+
IOS extended ACL "remark" lines automatically become comments when
|
|
28
|
+
converting to other formats of ACL.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def output_ios_named(self):
|
|
32
|
+
"""Output the Remark to IOS named format."""
|
|
33
|
+
return " remark " + self.data
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
# Build a table to unwind Cisco's weird inverse netmask.
|
|
37
|
+
# TODO (jathan): These don't actually get sorted properly, but it doesn't seem
|
|
38
|
+
# to have mattered up until now. Worth looking into it at some point, though.
|
|
39
|
+
inverse_mask_table = dict([(make_inverse_mask(x), x) for x in range(0, 33)])
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def handle_ios_match(a):
|
|
43
|
+
protocol, source, dest = a[:3]
|
|
44
|
+
extra = a[3:]
|
|
45
|
+
|
|
46
|
+
match = Matches()
|
|
47
|
+
modifiers = Modifiers()
|
|
48
|
+
|
|
49
|
+
if protocol:
|
|
50
|
+
match["protocol"] = [protocol]
|
|
51
|
+
|
|
52
|
+
for sd, arg in (("source", source), ("destination", dest)):
|
|
53
|
+
if isinstance(arg, list):
|
|
54
|
+
if arg[0] is not None:
|
|
55
|
+
match[sd + "-address"] = [arg[0]]
|
|
56
|
+
match[sd + "-port"] = arg[1]
|
|
57
|
+
else:
|
|
58
|
+
if arg is not None:
|
|
59
|
+
match[sd + "-address"] = [arg]
|
|
60
|
+
|
|
61
|
+
if "log" in extra:
|
|
62
|
+
modifiers["syslog"] = True
|
|
63
|
+
extra.remove("log")
|
|
64
|
+
|
|
65
|
+
if protocol == "icmp":
|
|
66
|
+
if len(extra) > 2:
|
|
67
|
+
raise NotImplementedError(extra)
|
|
68
|
+
if extra and isinstance(extra[0], tuple):
|
|
69
|
+
extra = extra[0]
|
|
70
|
+
if len(extra) >= 1:
|
|
71
|
+
match["icmp-type"] = [extra[0]]
|
|
72
|
+
if len(extra) >= 2:
|
|
73
|
+
match["icmp-code"] = [extra[1]]
|
|
74
|
+
elif protocol == "tcp":
|
|
75
|
+
if extra == ["established"]:
|
|
76
|
+
match["tcp-flags"] = [tcp_flag_specials["tcp-established"]]
|
|
77
|
+
elif extra:
|
|
78
|
+
raise NotImplementedError(extra)
|
|
79
|
+
elif extra:
|
|
80
|
+
raise NotImplementedError(extra)
|
|
81
|
+
|
|
82
|
+
return {"match": match, "modifiers": modifiers}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def handle_ios_acl(rows):
|
|
86
|
+
acl = ACL()
|
|
87
|
+
for d in rows:
|
|
88
|
+
if not d:
|
|
89
|
+
continue
|
|
90
|
+
for k, v in d.items():
|
|
91
|
+
if k == "no":
|
|
92
|
+
acl = ACL()
|
|
93
|
+
elif k == "name":
|
|
94
|
+
if acl.name:
|
|
95
|
+
if v != acl.name:
|
|
96
|
+
raise exceptions.ACLNameError(
|
|
97
|
+
f"Name '{v}' does not match ACL '{acl.name}'"
|
|
98
|
+
)
|
|
99
|
+
else:
|
|
100
|
+
acl.name = v
|
|
101
|
+
elif k == "term":
|
|
102
|
+
acl.terms.append(v)
|
|
103
|
+
elif k == "format":
|
|
104
|
+
acl.format = v
|
|
105
|
+
# Brocade receive-acl
|
|
106
|
+
elif k == "receive_acl":
|
|
107
|
+
acl.is_receive_acl = True
|
|
108
|
+
else:
|
|
109
|
+
raise RuntimeError(f'unknown key "{k}" (value {v})')
|
|
110
|
+
# In traditional ACLs, comments that belong to the first ACE are
|
|
111
|
+
# indistinguishable from comments that belong to the ACL.
|
|
112
|
+
# if acl.format == 'ios' and acl.terms:
|
|
113
|
+
if acl.format in ("ios", "ios_brocade") and acl.terms:
|
|
114
|
+
acl.comments += acl.terms[0].comments
|
|
115
|
+
acl.terms[0].comments = []
|
|
116
|
+
return acl
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
unary_port_operators = {
|
|
120
|
+
"eq": lambda x: [x],
|
|
121
|
+
"le": lambda x: [(0, x)],
|
|
122
|
+
"lt": lambda x: [(0, x - 1)],
|
|
123
|
+
"ge": lambda x: [(x, 65535)],
|
|
124
|
+
"gt": lambda x: [(x + 1, 65535)],
|
|
125
|
+
"neq": lambda x: [(0, x - 1), (x + 1, 65535)],
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
rules.update(
|
|
129
|
+
{
|
|
130
|
+
"ios_ip": "kw_any / host_ipv4 / ios_masked_ipv4",
|
|
131
|
+
"kw_any": ('"any"', None),
|
|
132
|
+
"host_ipv4": '"host", ts, ipv4',
|
|
133
|
+
S("ios_masked_ipv4"): (
|
|
134
|
+
"ipv4, ts, ipv4_inverse_mask",
|
|
135
|
+
# Python 3: Explicit tuple unpacking for string formatting
|
|
136
|
+
lambda x: TIP("%s/%d" % (x[0], x[1])),
|
|
137
|
+
),
|
|
138
|
+
"ipv4_inverse_mask": (
|
|
139
|
+
literals(inverse_mask_table),
|
|
140
|
+
lambda x: inverse_mask_table[TIP(x)],
|
|
141
|
+
),
|
|
142
|
+
"kw_ip": ('"ip"', None),
|
|
143
|
+
S("ios_match"): (
|
|
144
|
+
"kw_ip / protocol, ts, ios_ip, ts, ios_ip, (ts, ios_log)?",
|
|
145
|
+
handle_ios_match,
|
|
146
|
+
),
|
|
147
|
+
S("ios_tcp_port_match"): (
|
|
148
|
+
"tcp, ts, ios_ip_port, ts, ios_ip_port, (ts, established)?, (ts, ios_log)?",
|
|
149
|
+
handle_ios_match,
|
|
150
|
+
),
|
|
151
|
+
S("ios_udp_port_match"): (
|
|
152
|
+
"udp, ts, ios_ip_port, ts, ios_ip_port, (ts, ios_log)?",
|
|
153
|
+
handle_ios_match,
|
|
154
|
+
),
|
|
155
|
+
S("ios_ip_port"): "ios_ip, (ts, unary_port / ios_range)?",
|
|
156
|
+
S("unary_port"): (
|
|
157
|
+
"unary_port_operator, ts, port",
|
|
158
|
+
lambda x: unary_port_operators[x[0]](x[1]),
|
|
159
|
+
),
|
|
160
|
+
"unary_port_operator": literals(unary_port_operators),
|
|
161
|
+
S("ios_range"): ('"range", ts, port, ts, port', lambda xy: [(xy[0], xy[1])]),
|
|
162
|
+
"established": '"established"',
|
|
163
|
+
S("ios_icmp_match"): (
|
|
164
|
+
"icmp, ts, ios_ip, ts, ios_ip, (ts, ios_log)?, "
|
|
165
|
+
"(ts, ios_icmp_message / "
|
|
166
|
+
" (icmp_type, (ts, icmp_code)?))?, (ts, ios_log)?",
|
|
167
|
+
handle_ios_match,
|
|
168
|
+
),
|
|
169
|
+
"ios_icmp_message": (
|
|
170
|
+
literals(ios_icmp_messages),
|
|
171
|
+
lambda x: ios_icmp_messages[x],
|
|
172
|
+
),
|
|
173
|
+
"ios_action": '"permit" / "deny"',
|
|
174
|
+
"ios_log": '"log-input" / "log"',
|
|
175
|
+
S("ios_action_match"): (
|
|
176
|
+
"ios_action, ts, ios_tcp_port_match / "
|
|
177
|
+
"ios_udp_port_match / ios_icmp_match / ios_match",
|
|
178
|
+
lambda x: {"term": Term(action=x[0], **x[1])},
|
|
179
|
+
),
|
|
180
|
+
"ios_acl_line": "ios_acl_match_line / ios_acl_no_line",
|
|
181
|
+
S("ios_acl_match_line"): (
|
|
182
|
+
'"access-list", ts, digits, ts, ios_action_match',
|
|
183
|
+
lambda x: update(x[1], name=x[0], format="ios"),
|
|
184
|
+
),
|
|
185
|
+
S("ios_acl_no_line"): (
|
|
186
|
+
'"no", ts, "access-list", ts, digits',
|
|
187
|
+
lambda x: {"no": True, "name": x[0]},
|
|
188
|
+
),
|
|
189
|
+
"ios_ext_line": (
|
|
190
|
+
"ios_action_match / ios_ext_name_line / "
|
|
191
|
+
"ios_ext_no_line / ios_remark_line / "
|
|
192
|
+
"ios_rebind_acl_line / ios_rebind_receive_acl_line"
|
|
193
|
+
),
|
|
194
|
+
S("ios_ext_name_line"): (
|
|
195
|
+
'"ip", ts, "access-list", ts, "extended", ts, word',
|
|
196
|
+
lambda x: {"name": x[0], "format": "ios_named"},
|
|
197
|
+
),
|
|
198
|
+
S("ios_ext_no_line"): (
|
|
199
|
+
'"no", ts, "ip", ts, "access-list", ts, "extended", ts, word',
|
|
200
|
+
lambda x: {"no": True, "name": x[0]},
|
|
201
|
+
),
|
|
202
|
+
# Brocade "ip rebind-acl foo" or "ip rebind-receive-acl foo" syntax
|
|
203
|
+
S("ios_rebind_acl_line"): (
|
|
204
|
+
'"ip", ts, "rebind-acl", ts, word',
|
|
205
|
+
lambda x: {"name": x[0], "format": "ios_brocade"},
|
|
206
|
+
),
|
|
207
|
+
# Brocade "ip rebind-acl foo" or "ip rebind-receive-acl foo" syntax
|
|
208
|
+
S("ios_rebind_receive_acl_line"): (
|
|
209
|
+
'"ip", ts, "rebind-receive-acl", ts, word',
|
|
210
|
+
lambda x: {"name": x[0], "format": "ios_brocade", "receive_acl": True},
|
|
211
|
+
),
|
|
212
|
+
S("icomment"): ('"!", ts?, icomment_body', lambda x: x),
|
|
213
|
+
"icomment_body": ('-"\n"*', Comment),
|
|
214
|
+
S("ios_remark_line"): (
|
|
215
|
+
'("access-list", ts, digits_s, ts)?, "remark", ts, remark_body',
|
|
216
|
+
lambda x: x,
|
|
217
|
+
),
|
|
218
|
+
"remark_body": ('-"\n"*', Remark),
|
|
219
|
+
">ios_line<": ('ts?, (ios_acl_line / ios_ext_line / "end")?, ts?, icomment?'),
|
|
220
|
+
S("ios_acl"): ('(ios_line, "\n")*, ios_line', handle_ios_acl),
|
|
221
|
+
}
|
|
222
|
+
)
|