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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +13 -0
  5. data/.travis.yml +3 -0
  6. data/.yardopts +4 -0
  7. data/Gemfile +19 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +132 -0
  10. data/Rakefile +78 -0
  11. data/acl_examples/err-acl.txt +49 -0
  12. data/acl_examples/named-ext-acl.txt +12 -0
  13. data/acl_examples/named-std-acl.txt +6 -0
  14. data/acl_examples/numd-acl.txt +21 -0
  15. data/cisco_acl_intp.gemspec +31 -0
  16. data/lib/cisco_acl_intp/ace.rb +432 -0
  17. data/lib/cisco_acl_intp/ace_ip.rb +136 -0
  18. data/lib/cisco_acl_intp/ace_other_qualifiers.rb +102 -0
  19. data/lib/cisco_acl_intp/ace_port.rb +146 -0
  20. data/lib/cisco_acl_intp/ace_proto.rb +319 -0
  21. data/lib/cisco_acl_intp/ace_srcdst.rb +114 -0
  22. data/lib/cisco_acl_intp/ace_tcp_flags.rb +65 -0
  23. data/lib/cisco_acl_intp/acl.rb +272 -0
  24. data/lib/cisco_acl_intp/acl_base.rb +111 -0
  25. data/lib/cisco_acl_intp/parser.rb +3509 -0
  26. data/lib/cisco_acl_intp/parser.ry +1397 -0
  27. data/lib/cisco_acl_intp/scanner.rb +176 -0
  28. data/lib/cisco_acl_intp/scanner_special_token_handler.rb +66 -0
  29. data/lib/cisco_acl_intp/version.rb +5 -0
  30. data/lib/cisco_acl_intp.rb +9 -0
  31. data/spec/cisco_acl_intp/ace_ip_spec.rb +111 -0
  32. data/spec/cisco_acl_intp/ace_other_qualifier_spec.rb +63 -0
  33. data/spec/cisco_acl_intp/ace_port_spec.rb +214 -0
  34. data/spec/cisco_acl_intp/ace_proto_spec.rb +200 -0
  35. data/spec/cisco_acl_intp/ace_spec.rb +605 -0
  36. data/spec/cisco_acl_intp/ace_srcdst_spec.rb +296 -0
  37. data/spec/cisco_acl_intp/ace_tcp_flags_spec.rb +38 -0
  38. data/spec/cisco_acl_intp/acl_spec.rb +523 -0
  39. data/spec/cisco_acl_intp/cisco_acl_intp_spec.rb +7 -0
  40. data/spec/cisco_acl_intp/parser_spec.rb +53 -0
  41. data/spec/cisco_acl_intp/scanner_spec.rb +122 -0
  42. data/spec/conf/extacl_objgrp_token_seq.yml +36 -0
  43. data/spec/conf/extacl_token_seq.yml +88 -0
  44. data/spec/conf/extended_acl.yml +226 -0
  45. data/spec/conf/scanner_spec_data.yml +120 -0
  46. data/spec/conf/single_tokens.yml +235 -0
  47. data/spec/conf/stdacl_token_seq.yml +8 -0
  48. data/spec/conf/tokens1.yml +158 -0
  49. data/spec/conf/tokens2.yml +206 -0
  50. data/spec/parser_fullfill_patterns.rb +145 -0
  51. data/spec/spec_helper.rb +54 -0
  52. data/tools/check_acl.rb +48 -0
  53. 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: