cisco_acl_intp 0.0.1 → 0.0.2

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.travis.yml +2 -0
  4. data/.yardopts +1 -1
  5. data/Gemfile +5 -1
  6. data/README.md +76 -22
  7. data/Rakefile +18 -6
  8. data/cisco_acl_intp.gemspec +5 -5
  9. data/lib/cisco_acl_intp.rb +8 -0
  10. data/lib/cisco_acl_intp/ace.rb +36 -39
  11. data/lib/cisco_acl_intp/ace_ip.rb +73 -31
  12. data/lib/cisco_acl_intp/ace_other_qualifiers.rb +2 -2
  13. data/lib/cisco_acl_intp/ace_port.rb +114 -28
  14. data/lib/cisco_acl_intp/ace_proto.rb +160 -73
  15. data/lib/cisco_acl_intp/ace_srcdst.rb +57 -25
  16. data/lib/cisco_acl_intp/ace_tcp_flags.rb +1 -1
  17. data/lib/cisco_acl_intp/acl.rb +81 -35
  18. data/lib/cisco_acl_intp/acl_base.rb +65 -66
  19. data/lib/cisco_acl_intp/parser.rb +914 -1037
  20. data/lib/cisco_acl_intp/parser.ry +68 -215
  21. data/lib/cisco_acl_intp/parser_api.rb +248 -0
  22. data/lib/cisco_acl_intp/scanner.rb +58 -63
  23. data/lib/cisco_acl_intp/scanner_special_token_handler.rb +2 -4
  24. data/lib/cisco_acl_intp/version.rb +9 -1
  25. data/spec/cisco_acl_intp/ace_ip_spec.rb +45 -0
  26. data/spec/cisco_acl_intp/ace_port_spec.rb +119 -0
  27. data/spec/cisco_acl_intp/ace_proto_spec.rb +40 -1
  28. data/spec/cisco_acl_intp/ace_spec.rb +3 -3
  29. data/spec/cisco_acl_intp/ace_srcdst_spec.rb +95 -1
  30. data/spec/cisco_acl_intp/acl_base_spec.rb +60 -0
  31. data/spec/cisco_acl_intp/acl_spec.rb +2 -0
  32. data/spec/cisco_acl_intp/cisco_acl_intp_spec.rb +8 -0
  33. data/spec/cisco_acl_intp/parser_spec.rb +80 -2
  34. data/spec/cisco_acl_intp/scanner_spec.rb +0 -1
  35. data/spec/conf/extended_acl.yml +18 -18
  36. data/spec/parser_fullfill_patterns.rb +3 -3
  37. data/spec/spec_helper.rb +6 -0
  38. data/tools/check_acl.rb +23 -5
  39. metadata +27 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ca5d93222e696b7d5cbe8af83c2993454a7ce56f
4
- data.tar.gz: e6d9b5ce240ae6a494b11f46a461bdc6ac90ac27
3
+ metadata.gz: d664d74e52b4738c1835532f0fecefe1ee162ece
4
+ data.tar.gz: 56a40d167de808a4bf0ef778d8f443b01c408a22
5
5
  SHA512:
6
- metadata.gz: 0e7d8aa8410bd44bc5406424548936d6a245f76c4c473c64dfe9bb2834e9f8348ddb797b513317a699e3615b455a68a3e201e6a60ef464faf0c4a2df9303e921
7
- data.tar.gz: 37a36a2086e4106d327b08d6c157d829af96b2dfe807fd8fb008c52be07ddd6be0a6b221446d79e975f76a89a8428b1a34610f5f56b161cb94f95e1afffd3b9d
6
+ metadata.gz: 63c07906a0c2910a1cdbb6cb53b02cb9ef36c32b4138223c400147d8447f101b9c44fb9af211363a9a79be6f4dde533f448483975cb132fd6461a4e49a7cf463
7
+ data.tar.gz: c5208c436298dde049720eb9b5f15f41b09d482b696aa592c95220ec5fc6f779f2e8b4aebd2dda7539946d8eded55cdbfc4ba1a1b871afebefb1daf88b5d9cc2
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.travis.yml CHANGED
@@ -1,3 +1,5 @@
1
1
  language: ruby
2
+ script: 'rake travis'
2
3
  rvm:
4
+ - 1.9.3
3
5
  - 2.0.0
data/.yardopts CHANGED
@@ -1,4 +1,4 @@
1
1
  --exclude parser.rb
2
- --exclude spec/data/*
2
+ --exclude spec/**/*.rb
3
3
  --private
4
4
  --protected
data/Gemfile CHANGED
@@ -1,13 +1,17 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in cisco_acl_intp.gemspec
4
6
  gemspec
5
7
 
6
8
  group :development, :test do
9
+ gem 'coveralls', require: false
7
10
  gem 'racc', '~> 1.4.11'
8
11
  gem 'rake', '~> 10.1.1'
12
+ gem 'reek', '~> 1.3.6'
9
13
  gem 'rspec', '~> 2.14.1'
10
- gem 'rubocop', '~> 0.16.0' if RUBY_VERSION >= '1.9.0'
14
+ gem 'rubocop', '~> 0.18.1' if RUBY_VERSION >= '1.9.0'
11
15
  gem 'simplecov', '~> 0.8.2' if RUBY_VERSION >= '1.9.0'
12
16
  gem 'yard', '~> 0.8.7'
13
17
  end
data/README.md CHANGED
@@ -1,4 +1,8 @@
1
1
  # CiscoAclIntp
2
+ [![Gem Version](https://badge.fury.io/rb/cisco_acl_intp.png)](http://badge.fury.io/rb/cisco_acl_intp)
3
+ [![Build Status](https://travis-ci.org/stereocat/cisco_acl_intp.png?branch=master)](https://travis-ci.org/stereocat/cisco_acl_intp)
4
+ [![Dependency Status](https://gemnasium.com/stereocat/cisco_acl_intp.png)](https://gemnasium.com/stereocat/cisco_acl_intp)
5
+ [![Coverage Status](https://coveralls.io/repos/stereocat/cisco_acl_intp/badge.png?branch=master)](https://coveralls.io/r/stereocat/cisco_acl_intp?branch=master)
2
6
 
3
7
  CiscoAclIntp is a interpreter of Cisco IOS access control list (ACL).
4
8
 
@@ -52,28 +56,70 @@ CiscoAclIntp parser and output parser results.
52
56
  In directory `acl_examples`, there are some Cisco IOS ACL sample
53
57
  files. Run `check_acl.rb` with ACL sample files, like below.
54
58
 
55
- $ ~/cisco_acl_intp$ ruby tools/check_acl.rb -c -f acl_examples/numd-acl.txt
56
- acl name : 1
57
- access-list 1 permit 192.168.0.0 0.0.255.255
58
- access-list 1 deny any log
59
- acl name : 100
60
- access-list 100 remark General Internet Access
61
- access-list 100 permit icmp any any
62
- access-list 100 permit ip 192.168.0.0 0.0.255.255 any
63
- access-list 100 remark NTP
64
- access-list 100 permit tcp any host 210.197.74.200
65
- access-list 100 permit udp any eq ntp any eq ntp
66
- access-list 100 remark 6to4
67
- access-list 100 permit 41 any host 192.88.99.1
68
- access-list 100 permit ip any host 192.88.99.1
69
- access-list 100 remark others
70
- access-list 100 permit tcp any eq 0 any eq 0
71
- access-list 100 permit udp any eq 0 any eq 0
72
- access-list 100 deny ip any any log
73
- acl name : 110
74
- access-list 110 remark SPLIT_VPN
75
- access-list 110 permit ip 192.168.0.0 0.0.255.255 any
76
- $ ~/cisco_acl_intp$
59
+ ```
60
+ $ ruby tools/check_acl.rb -c term -f acl_examples/err-acl.txt
61
+ --------------------
62
+ in acl: 100, line: 6, near value: udp, (token: "udp")
63
+ in acl: 100, line: 8, near value: 100, (token: NUMBER)
64
+ in acl: 100, line: 11, Wrong protocol number: 256
65
+ in acl: 100, line: 14, near value: hoge, (token: error)
66
+ in acl: FA8-OUT, line: 4, Wrong protocol number: 65536
67
+ in acl: FA8-OUT, line: 7, Provided wildcard mask failed validation: 0.0.240.256 is invalid (IPv4 octets should be between 0 and 255).
68
+ in acl: FA8-OUT, line: 13, near value: up, (token: error)
69
+ --------------------
70
+ acl name : 1
71
+ access-list 1 permit 192.168.0.0 0.0.255.255
72
+ access-list 1 deny any log
73
+ acl name : 100
74
+ access-list 100 remark General Internet Access
75
+ access-list 100 permit icmp any any
76
+ access-list 100 permit ip 192.168.0.0 0.0.255.255 any
77
+ access-list 100 permit tcp any host 210.197.74.200
78
+ access-list 100 remark !wrong acl number!
79
+ access-list 100 remark !------cleared------!
80
+ access-list 100 remark !wrong header! caccess-list
81
+ access-list 100 remark !------cleared------!
82
+ access-list 100 permit 41 any host 192.88.99.1
83
+ access-list 100 remark !wrong ip proto number!
84
+ access-list 100 !! error !! 192.88.99.1
85
+ access-list 100 remark !------cleared------!
86
+ access-list 100 remark !wrong ip proto!
87
+ access-list 100 !! error !! 192.88.99.1
88
+ access-list 100 remark !------cleared------!
89
+ access-list 100 permit ip any host 192.88.99.1
90
+ access-list 100 remark others
91
+ access-list 100 permit tcp any eq 0 any eq 0
92
+ access-list 100 permit udp any eq 0 any eq 0
93
+ access-list 100 deny ip any any log
94
+ acl name : 10
95
+ access-list 10 !! error !! ntp
96
+ acl name : 110
97
+ access-list 110 remark SPLIT_VPN
98
+ access-list 110 permit ip 192.168.0.0 0.0.255.255 any
99
+ acl name : FA8-OUT
100
+ ip access-list extended FA8-OUT
101
+ deny udp any any eq bootpc
102
+ deny udp any any eq bootps
103
+ remark !argment error! 65536
104
+ !! error !! 65536
105
+ remark !------cleared------!
106
+ remark !argment error! 255 => 256
107
+ !! error !! 80
108
+ remark !------cleared------!
109
+ remark network access-list remark!!
110
+ permit tcp any any established
111
+ deny tcp any any syn rst
112
+ remark !syntax error! tcp -> tp (typo)
113
+ !! error !! hoge
114
+ remark !------cleared------!
115
+ permit ip any any log
116
+ acl name : remote-ipv4
117
+ ip access-list standard remote-ipv4
118
+ permit 192.168.0.0 0.0.255.255
119
+ remark standard access-list last deny!?
120
+ deny any log
121
+ $
122
+ ```
77
123
 
78
124
  By putting `-c` (`--color`) option, `check_acl.rb` outputs
79
125
  **color-coded ACL** according to type of each word. It can parse
@@ -117,8 +163,16 @@ table is "ACL object". "ACL object" is build by ACL components. For
117
163
  example, source/destination address obj, action obj, tcp/udp protocol
118
164
  obj,... See more detail in documents (see also, Documents section)
119
165
 
166
+ ### ACL Varidator Web Frontend
167
+
168
+ Front-end of ACL Varidator is at
169
+ [github](https://github.com/stereocat/cisco_acl_web). It not only can
170
+ parse (with CLI tool, it can only parse), but also search for ACL(ACE).
171
+
120
172
  ## Documents
121
173
 
174
+ * [API document generated with YARD](http://rubydoc.info/gems/cisco_acl_intp/)
175
+
122
176
  It can generate documents with YARD.
123
177
 
124
178
  $ rake yard
data/Rakefile CHANGED
@@ -1,6 +1,11 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
  require 'rake/clean'
6
+ require 'yard'
7
+ require 'yard/rake/yardoc_task'
8
+ require 'reek/rake/task'
4
9
 
5
10
  LIB_DIR = './lib'
6
11
  PACKAGE_NAME = 'cisco_acl_intp'
@@ -23,7 +28,8 @@ CLOBBER.include(
23
28
  CLASS_GRAPH_PNG
24
29
  )
25
30
 
26
- task default: [:parser, :spec]
31
+ task default: :travis
32
+ task travis: [:parser, :spec, :rubocop]
27
33
  task parser: [PARSER_RUBY]
28
34
  task spec: [SPEC_DATA_DIR]
29
35
 
@@ -47,12 +53,9 @@ RSpec::Core::RakeTask.new(fullspec: [:fullfill]) do |spec|
47
53
  spec.rspec_opts = '--format documentation --color'
48
54
  end
49
55
 
50
- # documentation by yard
51
- require 'yard'
52
- require 'yard/rake/yardoc_task'
53
56
  YARD::Rake::YardocTask.new do |task|
54
57
  # yardoc options in .yardopts
55
- task.files = ["#{LIB_DIR}/**/*.rb"]
58
+ task.files = FileList["#{LIB_DIR}/**/*.rb"]
56
59
  end
57
60
 
58
61
  task :docgraph do
@@ -61,7 +64,16 @@ task :docgraph do
61
64
  sh "dot -Tpng #{CLASS_GRAPH_DOT} -o #{CLASS_GRAPH_PNG}"
62
65
  end
63
66
 
64
- # rubocop settings
67
+ Reek::Rake::Task.new do |t|
68
+ t.fail_on_error = false
69
+ t.verbose = false
70
+ t.ruby_opts = ['-rubygems']
71
+ t.reek_opts = '--quiet'
72
+ t.source_files = FileList["#{LIB_DIR}/**/*.rb"].delete_if do |f|
73
+ f =~ /parser.rb/
74
+ end
75
+ end
76
+
65
77
  if RUBY_VERSION >= '1.9.0'
66
78
  task quality: :rubocop
67
79
  require 'rubocop/rake_task'
@@ -9,9 +9,9 @@ Gem::Specification.new do |spec|
9
9
  spec.version = CiscoAclIntp::VERSION
10
10
  spec.authors = ['stereocat']
11
11
  spec.email = ['stereocat@gmail.com']
12
- spec.description = %q{Cisco Access List Interpreter}
13
- spec.summary = %q{Cisco Access List Interpreter}
14
- spec.homepage = ''
12
+ spec.description = %q{Cisco ACL Interpreter}
13
+ spec.summary = %q{Cisco IOS Access Control List Interpreter}
14
+ spec.homepage = 'https://github.com/stereocat/cisco_acl_intp'
15
15
  spec.license = 'MIT'
16
16
 
17
17
  spec.files = `git ls-files`.split("\n")
@@ -20,8 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.require_paths = ['lib']
21
21
 
22
22
  spec.add_runtime_dependency 'netaddr', '~> 1.5.0'
23
- spec.add_runtime_dependency 'term-ansicolor', '~> 1.2.2'
24
- spec.add_development_dependency 'bundler', '~> 1.3'
23
+ spec.add_runtime_dependency 'term-ansicolor', '~> 1.3.0'
24
+ spec.add_development_dependency 'bundler', '~> 1.5.3'
25
25
  end
26
26
 
27
27
  ### Local variables:
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+
1
3
  require 'rubygems'
2
4
  require 'cisco_acl_intp/acl'
3
5
  require 'cisco_acl_intp/parser'
@@ -7,3 +9,9 @@ require 'cisco_acl_intp/version'
7
9
  # define scanner functions and ACL container classes
8
10
  module CiscoAclIntp
9
11
  end
12
+
13
+ ### Local variables:
14
+ ### mode: Ruby
15
+ ### coding: utf-8-unix
16
+ ### indent-tabs-mode: nil
17
+ ### End:
@@ -47,6 +47,20 @@ module CiscoAclIntp
47
47
  end
48
48
  end
49
49
 
50
+ # Error entry container
51
+ class ErrorAce < AceBase
52
+ attr_accessor :line
53
+
54
+ def initialize(line)
55
+ super({})
56
+ @line = line
57
+ end
58
+
59
+ def to_s
60
+ tag_error(sprintf('!! error !! %s', @line))
61
+ end
62
+ end
63
+
50
64
  # Remark entry container
51
65
  class RemarkAce < AceBase
52
66
  # @param [String] value Comment string
@@ -70,7 +84,7 @@ module CiscoAclIntp
70
84
  # Generate string for Cisco IOS access list
71
85
  # @return [String] Comment string
72
86
  def to_s
73
- sprintf ' remark %s', c_rmk(@comment.to_s)
87
+ sprintf 'remark %s', tag_remark(@comment.to_s)
74
88
  end
75
89
 
76
90
  # Search matched ACE
@@ -118,14 +132,14 @@ module CiscoAclIntp
118
132
  # Generate string for Cisco IOS access list
119
133
  # @return [String]
120
134
  def to_s
121
- sprintf 'evaluate %s', c_name(@recursive_name)
135
+ sprintf 'evaluate %s', tag_name(@recursive_name)
122
136
  end
123
137
 
124
138
  # Search matched ACE
125
139
  # @param [Hash] opts Options
126
- # return [Boolean] false, Recursive does not implemented yet
140
+ # return [Boolean]
141
+ # @todo for Recursive name matching is not implemented yet
127
142
  def matches?(opts = nil)
128
- ## TODO
129
143
  false
130
144
  end
131
145
  end
@@ -170,10 +184,10 @@ module CiscoAclIntp
170
184
  # @return [String]
171
185
  def to_s
172
186
  sprintf(
173
- ' %s %s %s',
174
- c_act(@action.to_s),
187
+ '%s %s %s',
188
+ tag_action(@action.to_s),
175
189
  @src_spec,
176
- @log_spec ? @log_spec : ''
190
+ tag_other_qualifier(@log_spec ? @log_spec : '')
177
191
  )
178
192
  end
179
193
 
@@ -184,7 +198,7 @@ module CiscoAclIntp
184
198
  # @raise [AclArgumentError] Invalid src_ip
185
199
  def matches?(opts)
186
200
  if opts.key?(:src_ip)
187
- @src_spec.ip_spec.matches?(opts[:src_ip])
201
+ @src_spec.matches?(opts[:src_ip])
188
202
  else
189
203
  fail AclArgumentError, 'Invalid match target src IP address'
190
204
  end
@@ -310,13 +324,13 @@ module CiscoAclIntp
310
324
  # @return [String]
311
325
  def to_s
312
326
  sprintf(
313
- ' %s %s %s %s %s %s',
314
- c_act(@action.to_s),
315
- c_pp(@protocol.to_s),
327
+ '%s %s %s %s %s %s',
328
+ tag_action(@action.to_s),
329
+ tag_protocol(@protocol.to_s),
316
330
  @src_spec,
317
331
  @dst_spec,
318
- @tcp_flags ? @tcp_flags : '',
319
- @tcp_other_qualifiers ? @tcp_other_qualifiers : ''
332
+ @tcp_flags,
333
+ @tcp_other_qualifiers
320
334
  )
321
335
  end
322
336
 
@@ -325,21 +339,19 @@ module CiscoAclIntp
325
339
  # @option opts [String] :protocol L3/L4 protocol name
326
340
  # (allows "tcp", "udp" and "icmp")
327
341
  # @option opts [String] :src_ip Source IP Address
328
- # @option opts [Integer] :src_port Source Port No.
342
+ # @option opts [Integer,String] :src_port Source Port No./Name
329
343
  # @option opts [String] :dst_ip Destination IP Address
330
- # @option opts [Integer] :dst_port Destination Port No.
344
+ # @option opts [Integer,String] :dst_port Destination Port No./Name
331
345
  # @return [Boolean] Matched or not
332
346
  # @raise [AclArgumentError]
333
347
  def matches?(opts)
334
348
  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])
349
+ match_protocol?(opts[:protocol]) &&
350
+ @src_spec.matches?(opts[:src_ip], opts[:src_port]) &&
351
+ @dst_spec.matches?(opts[:dst_ip], opts[:dst_port])
338
352
  else
339
353
  fail AclArgumentError, 'Invalid match target protocol'
340
354
  end
341
-
342
- (match_proto && match_src && match_dst)
343
355
  end
344
356
 
345
357
  private
@@ -350,30 +362,15 @@ module CiscoAclIntp
350
362
  # @raise [AclArgumentError]
351
363
  def match_protocol?(protocol)
352
364
  protocol_str = @protocol.to_s
353
- if protocol_str == 'ip'
354
- true # allow tcp/udp
365
+ if [protocol_str, protocol].include?('ip')
366
+ true # allow any of icmp/tcp/udp
355
367
  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.
368
+ # @todo what to do when NO name and only protocol number is
369
+ # specified? In principle, it must be compared by object.
359
370
  protocol == protocol_str
360
371
  end
361
372
  end
362
373
 
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
374
  # Set instance variables
378
375
  # return [AceIpProtoSpec] IP protocol object
379
376
  # raise [AclArgumentError]
@@ -12,20 +12,19 @@ module CiscoAclIntp
12
12
  # @param [NetAddr::CIDR] value IP address
13
13
  # (dotted decimal notation)
14
14
  # @return [NetAddr::CIDR]
15
- attr_accessor :ipaddr
15
+ attr_reader :ipaddr
16
16
 
17
17
  # @param [Integer] value Netmask length
18
18
  # @return [Integer]
19
- attr_accessor :netmask
19
+ attr_reader :netmask
20
20
 
21
21
  # @param [String] value Wildcard mask
22
22
  # (dotted decimal and bit flapped notation)
23
23
  # @return [String]
24
- attr_accessor :wildcard
24
+ attr_reader :wildcard
25
25
 
26
26
  def_delegator :@ipaddr, :ip, :ipaddr
27
- # `contained_ip?' method is cidr(ipaddr/nn) operation
28
- def_delegator :@ipaddr, :is_contained?, :contained_ip?
27
+
29
28
  # `matches?' method is wildcard mask operation
30
29
  def_delegators :@ipaddr, :matches?
31
30
 
@@ -40,7 +39,8 @@ module CiscoAclIntp
40
39
  # @return [AceIpSpec]
41
40
  def initialize(opts)
42
41
  if opts.key?(:ipaddr)
43
- define_addrinfo(opts)
42
+ @options = opts
43
+ define_addrinfo
44
44
  else
45
45
  fail AclArgumentError, 'Not specified IP address'
46
46
  end
@@ -59,13 +59,13 @@ module CiscoAclIntp
59
59
  def to_s
60
60
  if to_wmasked_ip_s == '0.0.0.0'
61
61
  # ip = '0.0.0.0' or wildcard = '255.255.255.255'
62
- c_ip('any')
62
+ tag_ip('any')
63
63
  else
64
64
  if @wildcard == '0.0.0.0'
65
65
  # /32 mask
66
- sprintf('%s %s', c_mask('host'), c_ip(@ipaddr.ip))
66
+ sprintf('%s %s', tag_mask('host'), tag_ip(@ipaddr.ip))
67
67
  else
68
- sprintf('%s %s', c_ip(to_wmasked_ip_s), c_mask(@wildcard))
68
+ sprintf('%s %s', tag_ip(to_wmasked_ip_s), tag_mask(@wildcard))
69
69
  end
70
70
  end
71
71
  end
@@ -75,54 +75,96 @@ module CiscoAclIntp
75
75
  def to_wmasked_ip_s
76
76
  ai = NetAddr.ip_to_i(@ipaddr.ip)
77
77
  mi = NetAddr.ip_to_i(@ipaddr.wildcard_mask)
78
- ami = ai & mi
79
- NetAddr.i_to_ip(ami)
78
+ NetAddr.i_to_ip(ai & mi)
79
+ end
80
+
81
+ # Check subnet contained this object or not.
82
+ # @param [String] address Subnet address string
83
+ # e.g. 192.168.0.0/24, 192.168.0.0/255.255.255.0
84
+ # @return [Boolean]
85
+ # @raise [NetAddr::ValidationError]
86
+ def contains?(address)
87
+ # `@ipaddr` contains(1), is same block(0),
88
+ # is `contained(-1), is not related(nil)
89
+ [0, 1].include?(@ipaddr.cmp(address))
80
90
  end
81
91
 
82
92
  private
83
93
 
94
+ # Convert table of IPv4 bit-flapped wildcard octet to bit length
95
+ OCTET_BIT_LENGTH = {
96
+ '255' => 0, '127' => 1, '63' => 2, '31' => 3,
97
+ '15' => 4, '7' => 5, '3' => 6, '1' => 7, '0' => 8
98
+ }
99
+
100
+ # Covnet IPv4 bit-flapped wildcard to netmask length
101
+ # @return [Fixnum] netmask length
102
+ # or `nil` when discontinuous-bits-wildcard-mask
103
+ def wildcard_bitlength
104
+ @wildcard.split(/\./).reduce(0) do |len, octet|
105
+ if len && OCTET_BIT_LENGTH.key?(octet)
106
+ len + OCTET_BIT_LENGTH[octet]
107
+ else
108
+ nil
109
+ end
110
+ end
111
+ end
112
+
84
113
  # 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)
114
+ def define_addrinfo
115
+ if @options.key?(:wildcard)
116
+ define_addrinfo_prefer_wildcard
117
+ else
118
+ define_addrinfo_by_netmask_or_default
119
+ end
120
+ end
121
+
122
+ # Set instance variables. assume that wildcard is primary option.
123
+ def define_addrinfo_prefer_wildcard
124
+ @wildcard = @options[:wildcard]
125
+ @netmask = wildcard_bitlength
126
+ if @netmask
127
+ @options[:netmask] = @netmask
128
+ define_addrinfo_with_netmask
129
+ else
130
+ define_addrinfo_with_wildcard
131
+ end
132
+ end
133
+
134
+ # Set instance variables. Secondary prioritize option is netmask,
135
+ # and third(last) one is default-mask
136
+ def define_addrinfo_by_netmask_or_default
137
+ if @options.key?(:netmask)
138
+ define_addrinfo_with_netmask
92
139
  else
93
- define_addrinfo_with_default_netmask(opts)
140
+ define_addrinfo_with_default_netmask
94
141
  end
95
142
  end
96
143
 
97
144
  # Set instance variables with ip/wildcard
98
- # @param [Hash] opts Options of constructor
99
- def define_addrinfo_with_wildcard(opts)
100
- @wildcard = opts[:wildcard]
145
+ def define_addrinfo_with_wildcard
101
146
  @ipaddr = NetAddr::CIDR.create(
102
- opts[:ipaddr],
147
+ @options[:ipaddr],
103
148
  WildcardMask: [@wildcard, true]
104
149
  )
105
- ## TBD : is it OK? must convert if possible?
106
150
  @netmask = nil
107
151
  end
108
152
 
109
153
  # Set instance variables with ip/netmask
110
- # @param [Hash] opts Options of constructor
111
- def define_addrinfo_with_netmask(opts)
112
- @netmask = opts[:netmask]
154
+ def define_addrinfo_with_netmask
155
+ @netmask = @options[:netmask]
113
156
  @ipaddr = NetAddr::CIDR.create(
114
- [opts[:ipaddr], @netmask].join('/')
157
+ [@options[:ipaddr], @netmask].join('/')
115
158
  )
116
159
  @wildcard = @ipaddr.wildcard_mask(true)
117
160
  end
118
161
 
119
162
  # Set instance variables with ip/default-netmask
120
- # @param [Hash] opts Options of constructor
121
- def define_addrinfo_with_default_netmask(opts)
163
+ def define_addrinfo_with_default_netmask
122
164
  # default mask
123
165
  @netmask = '255.255.255.255'
124
166
  @ipaddr = NetAddr::CIDR.create(
125
- [opts[:ipaddr], @netmask].join(' ')
167
+ [@options[:ipaddr], @netmask].join(' ')
126
168
  )
127
169
  @wildcard = @ipaddr.wildcard_mask(true)
128
170
  end