cisco_acl_intp 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +3 -0
- data/.yardopts +4 -0
- data/Gemfile +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +132 -0
- data/Rakefile +78 -0
- data/acl_examples/err-acl.txt +49 -0
- data/acl_examples/named-ext-acl.txt +12 -0
- data/acl_examples/named-std-acl.txt +6 -0
- data/acl_examples/numd-acl.txt +21 -0
- data/cisco_acl_intp.gemspec +31 -0
- data/lib/cisco_acl_intp/ace.rb +432 -0
- data/lib/cisco_acl_intp/ace_ip.rb +136 -0
- data/lib/cisco_acl_intp/ace_other_qualifiers.rb +102 -0
- data/lib/cisco_acl_intp/ace_port.rb +146 -0
- data/lib/cisco_acl_intp/ace_proto.rb +319 -0
- data/lib/cisco_acl_intp/ace_srcdst.rb +114 -0
- data/lib/cisco_acl_intp/ace_tcp_flags.rb +65 -0
- data/lib/cisco_acl_intp/acl.rb +272 -0
- data/lib/cisco_acl_intp/acl_base.rb +111 -0
- data/lib/cisco_acl_intp/parser.rb +3509 -0
- data/lib/cisco_acl_intp/parser.ry +1397 -0
- data/lib/cisco_acl_intp/scanner.rb +176 -0
- data/lib/cisco_acl_intp/scanner_special_token_handler.rb +66 -0
- data/lib/cisco_acl_intp/version.rb +5 -0
- data/lib/cisco_acl_intp.rb +9 -0
- data/spec/cisco_acl_intp/ace_ip_spec.rb +111 -0
- data/spec/cisco_acl_intp/ace_other_qualifier_spec.rb +63 -0
- data/spec/cisco_acl_intp/ace_port_spec.rb +214 -0
- data/spec/cisco_acl_intp/ace_proto_spec.rb +200 -0
- data/spec/cisco_acl_intp/ace_spec.rb +605 -0
- data/spec/cisco_acl_intp/ace_srcdst_spec.rb +296 -0
- data/spec/cisco_acl_intp/ace_tcp_flags_spec.rb +38 -0
- data/spec/cisco_acl_intp/acl_spec.rb +523 -0
- data/spec/cisco_acl_intp/cisco_acl_intp_spec.rb +7 -0
- data/spec/cisco_acl_intp/parser_spec.rb +53 -0
- data/spec/cisco_acl_intp/scanner_spec.rb +122 -0
- data/spec/conf/extacl_objgrp_token_seq.yml +36 -0
- data/spec/conf/extacl_token_seq.yml +88 -0
- data/spec/conf/extended_acl.yml +226 -0
- data/spec/conf/scanner_spec_data.yml +120 -0
- data/spec/conf/single_tokens.yml +235 -0
- data/spec/conf/stdacl_token_seq.yml +8 -0
- data/spec/conf/tokens1.yml +158 -0
- data/spec/conf/tokens2.yml +206 -0
- data/spec/parser_fullfill_patterns.rb +145 -0
- data/spec/spec_helper.rb +54 -0
- data/tools/check_acl.rb +48 -0
- metadata +159 -0
@@ -0,0 +1,432 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'cisco_acl_intp/ace_srcdst'
|
4
|
+
|
5
|
+
module CiscoAclIntp
|
6
|
+
# Access control entry base model
|
7
|
+
class AceBase < AclContainerBase
|
8
|
+
include Comparable
|
9
|
+
|
10
|
+
# @param [Integer] value ACL sequence number
|
11
|
+
# @return [Integer]
|
12
|
+
attr_accessor :seq_number
|
13
|
+
|
14
|
+
# Number used when ACE does not has sequence number
|
15
|
+
NO_SEQ_NUMBER = -1
|
16
|
+
|
17
|
+
# Constructor
|
18
|
+
# @param [Hash] opts
|
19
|
+
# @option opts [Integer] :number Sequence number
|
20
|
+
# @return [AceBase]
|
21
|
+
def initialize(opts)
|
22
|
+
@seq_number = opts[:number] || NO_SEQ_NUMBER
|
23
|
+
end
|
24
|
+
|
25
|
+
# Check this object has sequence number
|
26
|
+
# @return [Boolean]
|
27
|
+
def seq_number?
|
28
|
+
@seq_number > NO_SEQ_NUMBER
|
29
|
+
end
|
30
|
+
|
31
|
+
# Compare by sequence number
|
32
|
+
# @note Using "Comparable" module, '==' operator is defined by
|
33
|
+
# '<=>' operator. But ACE object will be compared by its value
|
34
|
+
# (comparison by the equivalence), instead of sequence
|
35
|
+
# number. The '==' operator will be overriden in child class.
|
36
|
+
# @param [AceBase] other RHS object
|
37
|
+
# @return [Integer] Compare with protocol/port number
|
38
|
+
def <=>(other)
|
39
|
+
@seq_number <=> other.seq_number
|
40
|
+
end
|
41
|
+
|
42
|
+
# Search matched ACE
|
43
|
+
# @return [Boolean] Matched or not
|
44
|
+
# @abstract
|
45
|
+
def matches?
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Remark entry container
|
51
|
+
class RemarkAce < AceBase
|
52
|
+
# @param [String] value Comment string
|
53
|
+
# @return [String]
|
54
|
+
attr_accessor :comment
|
55
|
+
|
56
|
+
# Constructor
|
57
|
+
# @param [String] str Comment string
|
58
|
+
# @return [RemarkAce]
|
59
|
+
def initialize(str)
|
60
|
+
@comment = str.strip
|
61
|
+
@seq_number = NO_SEQ_NUMBER # remark does not takes line number
|
62
|
+
end
|
63
|
+
|
64
|
+
# Check equality
|
65
|
+
# @return [Boolean] Compare with comment string
|
66
|
+
def ==(other)
|
67
|
+
@comment == other.comment
|
68
|
+
end
|
69
|
+
|
70
|
+
# Generate string for Cisco IOS access list
|
71
|
+
# @return [String] Comment string
|
72
|
+
def to_s
|
73
|
+
sprintf ' remark %s', c_rmk(@comment.to_s)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Search matched ACE
|
77
|
+
# @param [Hash] opts Options
|
78
|
+
# return [Boolean] false, Remark does not match anithyng.
|
79
|
+
def matches?(opts = nil)
|
80
|
+
false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Evaluate entry container
|
85
|
+
class EvaluateAce < AceBase
|
86
|
+
# @param [String] value Recutsive entry name
|
87
|
+
# @return [String]
|
88
|
+
attr_accessor :recursive_name
|
89
|
+
|
90
|
+
# Constructor
|
91
|
+
# @param [Hash] opts Options
|
92
|
+
# @option opts [Integer] :number Sequence number
|
93
|
+
# @option opts [String] :recursive_name Recursive entry name
|
94
|
+
# @return [EvaluateAce]
|
95
|
+
# @raise [AclArgumentError]
|
96
|
+
def initialize(opts)
|
97
|
+
super
|
98
|
+
@options = opts
|
99
|
+
@recursive_name = define_recursive_name
|
100
|
+
end
|
101
|
+
|
102
|
+
# Set instance variables
|
103
|
+
# return [String] Recursive entry name
|
104
|
+
# raise [AclArgumentError]
|
105
|
+
def define_recursive_name
|
106
|
+
if @options.key?(:recursive_name)
|
107
|
+
@options[:recursive_name]
|
108
|
+
else
|
109
|
+
fail AclArgumentError, 'name not specified'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# @return [Boolean] Compare with recursive entry name
|
114
|
+
def ==(other)
|
115
|
+
@recursive_name == other.recursive_name
|
116
|
+
end
|
117
|
+
|
118
|
+
# Generate string for Cisco IOS access list
|
119
|
+
# @return [String]
|
120
|
+
def to_s
|
121
|
+
sprintf 'evaluate %s', c_name(@recursive_name)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Search matched ACE
|
125
|
+
# @param [Hash] opts Options
|
126
|
+
# return [Boolean] false, Recursive does not implemented yet
|
127
|
+
def matches?(opts = nil)
|
128
|
+
## TODO
|
129
|
+
false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# ACE for standard access list
|
134
|
+
class StandardAce < AceBase
|
135
|
+
# @param [String] value Action
|
136
|
+
# @return [String]
|
137
|
+
attr_accessor :action
|
138
|
+
|
139
|
+
# @param [AceSrcDstSpec] value Source spec object
|
140
|
+
# @return [AceSrcDstSpec]
|
141
|
+
attr_accessor :src_spec
|
142
|
+
|
143
|
+
# @param [AceLogSpec] value Log spec object
|
144
|
+
# @return [AceLogSpec]
|
145
|
+
attr_accessor :log_spec
|
146
|
+
|
147
|
+
# Constructor
|
148
|
+
# @param [Hash] opts Options
|
149
|
+
# @option opts [Integer] :number Sequence number
|
150
|
+
# @option opts [String] :action Action (permit/deny)
|
151
|
+
# @option opts [AceSrcDstSpec] :src Source spec object
|
152
|
+
# @option opts [Hash] :src Source spec parmeters
|
153
|
+
# @option opts [AceLogSpec] :log Log spec object
|
154
|
+
# @return [StandardAce]
|
155
|
+
# @raise [AclArgumentError]
|
156
|
+
def initialize(opts)
|
157
|
+
super
|
158
|
+
@options = opts
|
159
|
+
@action = define_action
|
160
|
+
@src_spec = define_src_spec
|
161
|
+
@log_spec = define_log_spec
|
162
|
+
end
|
163
|
+
|
164
|
+
# @return [Boolean]
|
165
|
+
def ==(other)
|
166
|
+
@action == other.action && @src_spec == other.src_spec
|
167
|
+
end
|
168
|
+
|
169
|
+
# Generate string for Cisco IOS access list
|
170
|
+
# @return [String]
|
171
|
+
def to_s
|
172
|
+
sprintf(
|
173
|
+
' %s %s %s',
|
174
|
+
c_act(@action.to_s),
|
175
|
+
@src_spec,
|
176
|
+
@log_spec ? @log_spec : ''
|
177
|
+
)
|
178
|
+
end
|
179
|
+
|
180
|
+
# Search matched ACE
|
181
|
+
# @param [Hash] opts Options (target packet info)
|
182
|
+
# @option opts [String] :src_ip Source IP Address
|
183
|
+
# @return [Boolean] Matched or not
|
184
|
+
# @raise [AclArgumentError] Invalid src_ip
|
185
|
+
def matches?(opts)
|
186
|
+
if opts.key?(:src_ip)
|
187
|
+
@src_spec.ip_spec.matches?(opts[:src_ip])
|
188
|
+
else
|
189
|
+
fail AclArgumentError, 'Invalid match target src IP address'
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
private
|
194
|
+
|
195
|
+
# Set instance variables
|
196
|
+
# @return [String] Action string
|
197
|
+
# @raise [AclArgumentError]
|
198
|
+
def define_action
|
199
|
+
if @options.key?(:action)
|
200
|
+
@options[:action]
|
201
|
+
else
|
202
|
+
fail AclArgumentError, 'Not specified action'
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Set instance variables
|
207
|
+
# @return [AceSrcDstSpec] Source spec object
|
208
|
+
# @raise [AclArgumentError]
|
209
|
+
def define_src_spec
|
210
|
+
if @options.key?(:src)
|
211
|
+
src = @options[:src]
|
212
|
+
case src
|
213
|
+
when Hash
|
214
|
+
AceSrcDstSpec.new(src)
|
215
|
+
when AceSrcDstSpec
|
216
|
+
src
|
217
|
+
else
|
218
|
+
fail AclArgumentError, 'src spec: unknown class'
|
219
|
+
end
|
220
|
+
else
|
221
|
+
fail AclArgumentError, 'Not specified src spec'
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Set instance variables
|
226
|
+
# @return [String] Log spec object
|
227
|
+
# @raise [AclArgumentError]
|
228
|
+
def define_log_spec
|
229
|
+
@options[:log] || nil
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# ACE for extended access list
|
234
|
+
class ExtendedAce < StandardAce
|
235
|
+
# @param [String] value L3/L4 protocol
|
236
|
+
# @return [String]
|
237
|
+
attr_accessor :protocol
|
238
|
+
|
239
|
+
# @param [AceSrcDstSpec] value Destination spec object
|
240
|
+
# @return [AceSrcDstSpec]
|
241
|
+
attr_accessor :dst_spec
|
242
|
+
|
243
|
+
# @param [AceTcpFlagList] value
|
244
|
+
# TCP flags (used when '@protocol':tcp)
|
245
|
+
# @return [AceTcpFlagList]
|
246
|
+
attr_accessor :tcp_flags
|
247
|
+
|
248
|
+
# @param [AceOtherQualifierList] value
|
249
|
+
# TCP other qualifier list object (used when '@protocol':tcp)
|
250
|
+
# @return [AceOtherQualifierList]
|
251
|
+
attr_accessor :tcp_other_qualifiers
|
252
|
+
|
253
|
+
# Option,
|
254
|
+
# :src and :dst can handle multiple types of object generation,
|
255
|
+
# so that the argments can takes hash of AceSrcDstSpec.new or
|
256
|
+
# AceSrcDstSpec instance.
|
257
|
+
# :protocol and so on. (AceIpProtoSpec Object)
|
258
|
+
#
|
259
|
+
# about :protocol, it has specification of name and number
|
260
|
+
# (specified in internal of parser).
|
261
|
+
# basically, it is OK that specify only name.
|
262
|
+
# (does it convert name <=> number each oether?)
|
263
|
+
# (does it use number?
|
264
|
+
#
|
265
|
+
|
266
|
+
# Constructor
|
267
|
+
# @param [Hash] opts Options
|
268
|
+
# @option opts [String] :protocol L3/L4 protocol
|
269
|
+
# @option opts [Integer] :number Protocol/Port number
|
270
|
+
# @option opts [String] :action Action
|
271
|
+
# @option opts [AceSrcDstSpec] :src Source spec object
|
272
|
+
# @option opts [Hash] :src Source spec parmeters
|
273
|
+
# @option opts [AceSrcDstSpec] :dst Destination spec object
|
274
|
+
# @option opts [Hash] :dst Destination spec parmeters
|
275
|
+
# @option opts [AceTcpFlagList] :tcp_port_qualifier
|
276
|
+
# TCP Flags object
|
277
|
+
# @raise [AclArgumentError]
|
278
|
+
# @return [ExtendACE]
|
279
|
+
#
|
280
|
+
# @example Construct ACE object
|
281
|
+
# ExtendACE.new(
|
282
|
+
# :protocol => 'tcp',
|
283
|
+
# :number => 10,
|
284
|
+
# :action => 'permit',
|
285
|
+
# :src => { :ipaddr => '192.168.3.0', :wildcard => '0.0.0.127' },
|
286
|
+
# :dst => { :ipaddr => '172.30.0.0', :wildcard => '0.0.7.127',
|
287
|
+
# :operator => 'eq', :begin_port => 80 })
|
288
|
+
#
|
289
|
+
def initialize(opts)
|
290
|
+
super
|
291
|
+
@options = opts
|
292
|
+
@protocol = define_protocol
|
293
|
+
@dst_spec = define_dst_spec
|
294
|
+
@tcp_flags = define_tcp_flags
|
295
|
+
@tcp_other_qualifiers = nil # not yet.
|
296
|
+
end
|
297
|
+
|
298
|
+
# @param [ExtendACE] other RHS object
|
299
|
+
# @return [Boolean]
|
300
|
+
def ==(other)
|
301
|
+
@action == other.action &&
|
302
|
+
@protocol == other.protocol &&
|
303
|
+
@src_spec == other.src_spec &&
|
304
|
+
@dst_spec == other.dst_spec &&
|
305
|
+
@tcp_flags == other.tcp_flags
|
306
|
+
## does it need to compare? : tcp_other_qualifiers
|
307
|
+
end
|
308
|
+
|
309
|
+
# Generate string for Cisco IOS access list
|
310
|
+
# @return [String]
|
311
|
+
def to_s
|
312
|
+
sprintf(
|
313
|
+
' %s %s %s %s %s %s',
|
314
|
+
c_act(@action.to_s),
|
315
|
+
c_pp(@protocol.to_s),
|
316
|
+
@src_spec,
|
317
|
+
@dst_spec,
|
318
|
+
@tcp_flags ? @tcp_flags : '',
|
319
|
+
@tcp_other_qualifiers ? @tcp_other_qualifiers : ''
|
320
|
+
)
|
321
|
+
end
|
322
|
+
|
323
|
+
# Search matched ACE
|
324
|
+
# @param [Hash] opts Options (target packet info)
|
325
|
+
# @option opts [String] :protocol L3/L4 protocol name
|
326
|
+
# (allows "tcp", "udp" and "icmp")
|
327
|
+
# @option opts [String] :src_ip Source IP Address
|
328
|
+
# @option opts [Integer] :src_port Source Port No.
|
329
|
+
# @option opts [String] :dst_ip Destination IP Address
|
330
|
+
# @option opts [Integer] :dst_port Destination Port No.
|
331
|
+
# @return [Boolean] Matched or not
|
332
|
+
# @raise [AclArgumentError]
|
333
|
+
def matches?(opts)
|
334
|
+
if opts.key?(:protocol)
|
335
|
+
match_proto = match_protocol?(opts[:protocol])
|
336
|
+
match_src = match_addr_port?(@src_spec, opts[:src_ip], opts[:src_port])
|
337
|
+
match_dst = match_addr_port?(@dst_spec, opts[:dst_ip], opts[:dst_port])
|
338
|
+
else
|
339
|
+
fail AclArgumentError, 'Invalid match target protocol'
|
340
|
+
end
|
341
|
+
|
342
|
+
(match_proto && match_src && match_dst)
|
343
|
+
end
|
344
|
+
|
345
|
+
private
|
346
|
+
|
347
|
+
# check protocol
|
348
|
+
# @option protocol [AceProtoSpecBase] protocol
|
349
|
+
# @return [Boolean] Matched or not
|
350
|
+
# @raise [AclArgumentError]
|
351
|
+
def match_protocol?(protocol)
|
352
|
+
protocol_str = @protocol.to_s
|
353
|
+
if protocol_str == 'ip'
|
354
|
+
true # allow tcp/udp
|
355
|
+
else
|
356
|
+
## TBD
|
357
|
+
## what to do when NO name and only protocol number is specified?
|
358
|
+
# In principle, it must be compared by object.
|
359
|
+
protocol == protocol_str
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
# check src/dst address
|
364
|
+
# @option srcdst_spec [AceSrcDstSpec] src/dst address/port
|
365
|
+
# @option ip [String] ip addr to compare
|
366
|
+
# @option port [Integer] port number to compare
|
367
|
+
# @return [Boolean] Matched or not
|
368
|
+
# @raise [AclArgumentError]
|
369
|
+
def match_addr_port?(srcdst_spec, ip, port)
|
370
|
+
if ip
|
371
|
+
srcdst_spec.matches?(ip, port)
|
372
|
+
else
|
373
|
+
fail AclArgumentError, 'Not specified match target IP Addr'
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# Set instance variables
|
378
|
+
# return [AceIpProtoSpec] IP protocol object
|
379
|
+
# raise [AclArgumentError]
|
380
|
+
def define_protocol
|
381
|
+
if @options.key?(:protocol)
|
382
|
+
protocol = @options[:protocol]
|
383
|
+
case protocol
|
384
|
+
when AceIpProtoSpec
|
385
|
+
protocol
|
386
|
+
else
|
387
|
+
AceIpProtoSpec.new(
|
388
|
+
name: protocol,
|
389
|
+
number: @options[:protocol_num]
|
390
|
+
)
|
391
|
+
end
|
392
|
+
else
|
393
|
+
fail AclArgumentError, 'Not specified IP protocol'
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
# Set instance variables
|
398
|
+
# @return [AceSrcDstSpec] Destination spec object
|
399
|
+
# @raise [AclArgumentError]
|
400
|
+
def define_dst_spec
|
401
|
+
if @options.key?(:dst)
|
402
|
+
dst = @options[:dst]
|
403
|
+
case dst
|
404
|
+
when Hash
|
405
|
+
AceSrcDstSpec.new(dst)
|
406
|
+
when AceSrcDstSpec
|
407
|
+
dst
|
408
|
+
else
|
409
|
+
fail AclArgumentError, 'Dst spec: unknown class'
|
410
|
+
end
|
411
|
+
else
|
412
|
+
fail AclArgumentError, 'Not specified dst spec'
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# Set instance variables
|
417
|
+
# @return [AceOtherQualifierList]
|
418
|
+
def define_tcp_flags
|
419
|
+
if @protocol.name == 'tcp' && @options.key?(:tcp_flags_qualifier)
|
420
|
+
@options[:tcp_flags_qualifier]
|
421
|
+
else
|
422
|
+
nil
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
end # module
|
427
|
+
|
428
|
+
### Local variables:
|
429
|
+
### mode: Ruby
|
430
|
+
### coding: utf-8-unix
|
431
|
+
### indent-tabs-mode: nil
|
432
|
+
### End:
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'netaddr'
|
5
|
+
require 'cisco_acl_intp/acl_base'
|
6
|
+
|
7
|
+
module CiscoAclIntp
|
8
|
+
# IP Address and Wildcard mask container
|
9
|
+
class AceIpSpec < AclContainerBase
|
10
|
+
extend Forwardable
|
11
|
+
|
12
|
+
# @param [NetAddr::CIDR] value IP address
|
13
|
+
# (dotted decimal notation)
|
14
|
+
# @return [NetAddr::CIDR]
|
15
|
+
attr_accessor :ipaddr
|
16
|
+
|
17
|
+
# @param [Integer] value Netmask length
|
18
|
+
# @return [Integer]
|
19
|
+
attr_accessor :netmask
|
20
|
+
|
21
|
+
# @param [String] value Wildcard mask
|
22
|
+
# (dotted decimal and bit flapped notation)
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :wildcard
|
25
|
+
|
26
|
+
def_delegator :@ipaddr, :ip, :ipaddr
|
27
|
+
# `contained_ip?' method is cidr(ipaddr/nn) operation
|
28
|
+
def_delegator :@ipaddr, :is_contained?, :contained_ip?
|
29
|
+
# `matches?' method is wildcard mask operation
|
30
|
+
def_delegators :@ipaddr, :matches?
|
31
|
+
|
32
|
+
# Constructor
|
33
|
+
# @param [Hash] opts Options
|
34
|
+
# @option opts [String] :ipaddr IP address
|
35
|
+
# (dotted decimal notation)
|
36
|
+
# @option opts [String] :wildcard Wildcard mask
|
37
|
+
# (dotted decimal and bit flipped notation)
|
38
|
+
# @option opts [Integer] :netmask Network Mask Length
|
39
|
+
# @raise [AclArgumentError]
|
40
|
+
# @return [AceIpSpec]
|
41
|
+
def initialize(opts)
|
42
|
+
if opts.key?(:ipaddr)
|
43
|
+
define_addrinfo(opts)
|
44
|
+
else
|
45
|
+
fail AclArgumentError, 'Not specified IP address'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @param [AceIpSpec] other RHS Object
|
50
|
+
# @return [Boolean]
|
51
|
+
def ==(other)
|
52
|
+
@ipaddr == other.ipaddr &&
|
53
|
+
@netmask == other.netmask &&
|
54
|
+
@wildcard == other.wildcard
|
55
|
+
end
|
56
|
+
|
57
|
+
# Generate string for Cisco IOS access list
|
58
|
+
# @return [String]
|
59
|
+
def to_s
|
60
|
+
if to_wmasked_ip_s == '0.0.0.0'
|
61
|
+
# ip = '0.0.0.0' or wildcard = '255.255.255.255'
|
62
|
+
c_ip('any')
|
63
|
+
else
|
64
|
+
if @wildcard == '0.0.0.0'
|
65
|
+
# /32 mask
|
66
|
+
sprintf('%s %s', c_mask('host'), c_ip(@ipaddr.ip))
|
67
|
+
else
|
68
|
+
sprintf('%s %s', c_ip(to_wmasked_ip_s), c_mask(@wildcard))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Generate wildcard-masked ip address string
|
74
|
+
# @return [String] wildcard-masked ip address string
|
75
|
+
def to_wmasked_ip_s
|
76
|
+
ai = NetAddr.ip_to_i(@ipaddr.ip)
|
77
|
+
mi = NetAddr.ip_to_i(@ipaddr.wildcard_mask)
|
78
|
+
ami = ai & mi
|
79
|
+
NetAddr.i_to_ip(ami)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
# Set instance variables
|
85
|
+
# @param [Hash] opts Options of constructor
|
86
|
+
def define_addrinfo(opts)
|
87
|
+
case
|
88
|
+
when opts[:wildcard]
|
89
|
+
define_addrinfo_with_wildcard(opts)
|
90
|
+
when opts[:netmask]
|
91
|
+
define_addrinfo_with_netmask(opts)
|
92
|
+
else
|
93
|
+
define_addrinfo_with_default_netmask(opts)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Set instance variables with ip/wildcard
|
98
|
+
# @param [Hash] opts Options of constructor
|
99
|
+
def define_addrinfo_with_wildcard(opts)
|
100
|
+
@wildcard = opts[:wildcard]
|
101
|
+
@ipaddr = NetAddr::CIDR.create(
|
102
|
+
opts[:ipaddr],
|
103
|
+
WildcardMask: [@wildcard, true]
|
104
|
+
)
|
105
|
+
## TBD : is it OK? must convert if possible?
|
106
|
+
@netmask = nil
|
107
|
+
end
|
108
|
+
|
109
|
+
# Set instance variables with ip/netmask
|
110
|
+
# @param [Hash] opts Options of constructor
|
111
|
+
def define_addrinfo_with_netmask(opts)
|
112
|
+
@netmask = opts[:netmask]
|
113
|
+
@ipaddr = NetAddr::CIDR.create(
|
114
|
+
[opts[:ipaddr], @netmask].join('/')
|
115
|
+
)
|
116
|
+
@wildcard = @ipaddr.wildcard_mask(true)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Set instance variables with ip/default-netmask
|
120
|
+
# @param [Hash] opts Options of constructor
|
121
|
+
def define_addrinfo_with_default_netmask(opts)
|
122
|
+
# default mask
|
123
|
+
@netmask = '255.255.255.255'
|
124
|
+
@ipaddr = NetAddr::CIDR.create(
|
125
|
+
[opts[:ipaddr], @netmask].join(' ')
|
126
|
+
)
|
127
|
+
@wildcard = @ipaddr.wildcard_mask(true)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end # module
|
131
|
+
|
132
|
+
### Local variables:
|
133
|
+
### mode: Ruby
|
134
|
+
### coding: utf-8-unix
|
135
|
+
### indent-tabs-mode: nil
|
136
|
+
### End:
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
require 'forwardable'
|
4
|
+
require 'cisco_acl_intp/acl_base'
|
5
|
+
|
6
|
+
module CiscoAclIntp
|
7
|
+
# List of other-qualifiers for extended ace
|
8
|
+
class AceOtherQualifierList < AclContainerBase
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
# @param [Array] value List of {AceOtherQualifierList} object
|
12
|
+
# @return [Array]
|
13
|
+
attr_accessor :list
|
14
|
+
|
15
|
+
def_delegators :@list, :push, :pop, :shift, :unshift, :size, :length
|
16
|
+
|
17
|
+
# Constructor
|
18
|
+
# @return [AceOtherQualifierList]
|
19
|
+
def initialize
|
20
|
+
@list = []
|
21
|
+
end
|
22
|
+
|
23
|
+
# Generate string for Cisco IOS access list
|
24
|
+
# @return [String]
|
25
|
+
def to_s
|
26
|
+
c_pp(@list.map { | each | each.to_s }.join(' '))
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param [AceOtherQualifierList] other RHS Object
|
30
|
+
# @return [Boolean]
|
31
|
+
def ==(other)
|
32
|
+
@list == other.list
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Access list entry qualifier base
|
37
|
+
class AceOtherQualifierBase < AclContainerBase
|
38
|
+
end
|
39
|
+
|
40
|
+
# Log spec container
|
41
|
+
class AceLogSpec < AceOtherQualifierBase
|
42
|
+
# @param [String] value Log cookie
|
43
|
+
# @return [String]
|
44
|
+
attr_accessor :cookie
|
45
|
+
|
46
|
+
# Specified log-input logging?
|
47
|
+
# @return [Boolean]
|
48
|
+
attr_reader :input
|
49
|
+
|
50
|
+
# alias as boolean method
|
51
|
+
# @return [Boolean]
|
52
|
+
alias_method(:input?, :input)
|
53
|
+
|
54
|
+
# Constructor
|
55
|
+
# @param [String] cookie Log cookie
|
56
|
+
# @param [Boolean] input set true 'log-input' logging
|
57
|
+
# @return [AceLogSpec]
|
58
|
+
def initialize(cookie = nil, input = false)
|
59
|
+
@input = input
|
60
|
+
@cookie = cookie
|
61
|
+
end
|
62
|
+
|
63
|
+
# Generate string for Cisco IOS access list
|
64
|
+
# @return [String]
|
65
|
+
def to_s
|
66
|
+
sprintf(
|
67
|
+
'%s %s',
|
68
|
+
@input ? 'log-input' : 'log',
|
69
|
+
@cookie ? @cookie : ''
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Recursive qualifier container
|
75
|
+
class AceRecursiveQualifier < AceOtherQualifierBase
|
76
|
+
# @param [String] value Recursive name
|
77
|
+
# @return [String]
|
78
|
+
attr_accessor :recursive_name
|
79
|
+
|
80
|
+
# Constructor
|
81
|
+
# @param [String] name Recursive name
|
82
|
+
def initialize(name)
|
83
|
+
if name && (!name.empty?)
|
84
|
+
@recursive_name = name
|
85
|
+
else
|
86
|
+
fail AclArgumentError, 'Not specified recursive name'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Generate string for Cisco IOS access list
|
91
|
+
# @return [String]
|
92
|
+
def to_s
|
93
|
+
sprintf 'reflect %s', c_name(@recursive_name)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end # module
|
97
|
+
|
98
|
+
### Local variables:
|
99
|
+
### mode: Ruby
|
100
|
+
### coding: utf-8-unix
|
101
|
+
### indent-tabs-mode: nil
|
102
|
+
### End:
|