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,158 @@
1
+ :acl:
2
+ - :data: 'access-list'
3
+ :valid: true
4
+ - :data: 'access-lsit'
5
+ :msg: "typo <access-list>"
6
+ :valid: false
7
+ :stdacl_num:
8
+ - :data: "0"
9
+ :msg: "area1 lower out of range"
10
+ :valid: false
11
+ - :data: "1"
12
+ :msg: "area1 lower-bound"
13
+ :valid: true
14
+ - :data: "99"
15
+ :msg: "area1 upper-bound"
16
+ :valid: true
17
+ - :data: "1299"
18
+ :msg: "area2 lower out of range"
19
+ :valid: false
20
+ - :data: "1300"
21
+ :msg: "area2 lower-bound"
22
+ :valid: true
23
+ - :data: "1999"
24
+ :msg: "area2 upper-bound"
25
+ :valid: true
26
+ :extacl_num:
27
+ - :data: "100"
28
+ :valid: true
29
+ :msg: "area1 lower-bound"
30
+ - :data: "199"
31
+ :valid: true
32
+ :msg: "area1 upper-bound"
33
+ # - :data: "99"
34
+ # :valid: false
35
+ - :data: "200"
36
+ :valid: false
37
+ :msg: "area1 upper out of range"
38
+ - :data: "2000"
39
+ :valid: true
40
+ :msg: "area2 lower-bound"
41
+ - :data: "2699"
42
+ :valid: true
43
+ :msg: "area2 upper-bound"
44
+ # - :data: "1999"
45
+ # :valid: false
46
+ - :data: "2700"
47
+ :valid: false
48
+ :msg: "area2 upper out of range"
49
+ :dynamic_spec:
50
+ - :data: ''
51
+ :valid: true
52
+ - :data: 'dynamic dynamicname'
53
+ :valid: true
54
+ - :data: 'dynamic dynamicname timeout 3'
55
+ :valid: true
56
+ - :data: 'dynamic dynamicname timeout'
57
+ :valid: false
58
+ :msg: "missing timeout <min>"
59
+ - :data: 'dnamic dynamicname'
60
+ :valid: false
61
+ :msg: "typo <dynamic>"
62
+ :action:
63
+ - :data: ''
64
+ :msg: 'missing <action>'
65
+ :valid: false
66
+ - :data: 'permit'
67
+ :valid: true
68
+ - :data: 'deny'
69
+ :valid: true
70
+ - :data: 'drop'
71
+ :msg: "unknown action or typo"
72
+ :valid: false
73
+ :ip_proto:
74
+ - :data: ''
75
+ :msg: 'missing <protocol>'
76
+ :valid: false
77
+ - :data: 'ip'
78
+ :valid: true
79
+ - :data: 'ahp'
80
+ :valid: true
81
+ - :data: '0'
82
+ :msg: 'lower bound'
83
+ :valid: true
84
+ - :data: '255'
85
+ :msg: 'upper bound'
86
+ :valid: true
87
+ - :data: '256'
88
+ :msg: 'out of range'
89
+ :valid: false
90
+ :ip_spec1:
91
+ - :data: 'any'
92
+ :valid: true
93
+ - :data: 'host 192.168.0.1'
94
+ :valid: true
95
+ - :data: '192.168.0.0 0.0.0.128'
96
+ :valid: true
97
+ - :data: '192.168.0.2'
98
+ :valid: false
99
+ :msg: 'missing <host>'
100
+ - :data: '1921.68.0.2'
101
+ :valid: false
102
+ :msg: 'ip: out of range'
103
+ :ip_spec2:
104
+ - :data: 'any'
105
+ :valid: true
106
+ - :data: 'host 10.1.0.1'
107
+ :valid: true
108
+ - :data: '10.1.0.0 0.0.128.255'
109
+ :valid: true
110
+ - :data: '10.1.0.2'
111
+ :valid: false
112
+ :msg: 'missing <host>'
113
+ - :data: '10.1.0.256'
114
+ :valid: false
115
+ :msg: 'ip: out of range'
116
+ :icmp_proto:
117
+ - :data: ""
118
+ :valid: false
119
+ :msg: 'missing <icmp>'
120
+ - :data: "icmp"
121
+ :valid: true
122
+ :icmp_qualifier:
123
+ - :data: ""
124
+ :valid: true
125
+ - :data: 'administratively-prohibited'
126
+ :valid: true
127
+ - :data: '0'
128
+ :valid: true
129
+ :msg: "icmp type num only"
130
+ - :data: '0 255'
131
+ :valid: true
132
+ :msg: "icmp type/code num"
133
+ # - :data: "256 0"
134
+ # :valid: false
135
+ # # "type num: out of range"
136
+ # todo : "not implemented: icmp_qualifier type num check"
137
+ # - :data: "0 256"
138
+ # :valid: false
139
+ # # code num: out of range
140
+ # todo : "not implemented: icmp_qualifier code num check"
141
+ :std_acl_log_spec:
142
+ - :data: ""
143
+ :valid: true
144
+ - :data: "log"
145
+ :valid: true
146
+ - :data: "log logcookie"
147
+ :valid: true
148
+ :ext_acl_log_spec:
149
+ - :data: ""
150
+ :valid: true
151
+ - :data: "log"
152
+ :valid: true
153
+ - :data: "log logcookie"
154
+ :valid: true
155
+ - :data: "log-input"
156
+ :valid: true
157
+ - :data: "log-input logcookie"
158
+ :valid: true
@@ -0,0 +1,206 @@
1
+ :acl:
2
+ - :data: 'access-list'
3
+ :valid: true
4
+ :stdacl_num:
5
+ - :data: "1"
6
+ :valid: true
7
+ :msg: "area1 lower-bound"
8
+ :extacl_num:
9
+ - :data: "100"
10
+ :valid: true
11
+ :msg: "area1 lower-bound"
12
+ :dynamic_spec:
13
+ - :data: ''
14
+ :valid: true
15
+ - :data: 'dynamic dynamicname'
16
+ :valid: true
17
+ - :data: 'dynamic dynamicname timeout 3'
18
+ :valid: true
19
+ - :data: 'dynamic dynamicname timeout'
20
+ :valid: false
21
+ :msg: "missing timeout <min>"
22
+ - :data: 'dnamic dynamicname'
23
+ :valid: false
24
+ :msg: "typo <dynamic>"
25
+ :action:
26
+ - :data: 'permit'
27
+ :valid: true
28
+ - :data: 'deny'
29
+ :valid: true
30
+ :tcp_proto:
31
+ - :data: 'tcp'
32
+ :valid: true
33
+ :udp_proto:
34
+ - :data: 'udp'
35
+ :valid: true
36
+ :tcpudp_proto:
37
+ - :data: 'tcp'
38
+ :valid: true
39
+ - :data: 'udp'
40
+ :valid: true
41
+ - :data: 'object-group svgrp'
42
+ :valid: true
43
+ :ip_spec1:
44
+ - :data: 'any'
45
+ :valid: true
46
+ - :data: 'host 192.168.0.1'
47
+ :valid: true
48
+ - :data: '192.168.0.0 0.0.0.128'
49
+ :valid: true
50
+ - :data: '192.168.0.2'
51
+ :valid: false
52
+ :msg: 'missing <host>'
53
+ - :data: '1921.68.0.2'
54
+ :valid: false
55
+ :msg: 'ip: out of range'
56
+ :ip_spec2:
57
+ - :data: 'any'
58
+ :valid: true
59
+ - :data: 'host 10.1.0.1'
60
+ :valid: true
61
+ - :data: '10.1.0.0 0.0.128.255'
62
+ :valid: true
63
+ - :data: '10.1.0.2'
64
+ :valid: false
65
+ :msg: 'missing <host>'
66
+ - :data: '10.1.0.256'
67
+ :valid: false
68
+ :msg: 'ip: out of range'
69
+ :ip_spec_objgrp1:
70
+ - :data: 'any'
71
+ :valid: true
72
+ - :data: 'host 192.168.0.1'
73
+ :valid: true
74
+ - :data: '192.168.0.0 0.0.0.128'
75
+ :valid: true
76
+ - :data: 'object-group nwgrp1'
77
+ :valid: true
78
+ :ip_spec_objgrp2:
79
+ - :data: 'any'
80
+ :valid: true
81
+ - :data: 'host 10.1.0.1'
82
+ :valid: true
83
+ - :data: '10.1.0.0 0.0.128.255'
84
+ :valid: true
85
+ - :data: 'object-group nwgrp2'
86
+ :valid: true
87
+ :null_port:
88
+ - :data: ""
89
+ :valid: true
90
+ :tcp_port_spec1:
91
+ - :data: ""
92
+ :valid: true
93
+ - :data: "eq 80"
94
+ :valid: true
95
+ - :data: "eq any"
96
+ :valid: false
97
+ :msg: "unknown port-prot-name"
98
+ - :data: "lt ftp"
99
+ :valid: true
100
+ - :data: "gt telnet"
101
+ :valid: true
102
+ - :data: "range 53 443"
103
+ :valid: true
104
+ :tcp_port_spec2:
105
+ - :data: ""
106
+ :valid: true
107
+ - :data: "eq www"
108
+ :valid: true
109
+ - :data: "lt domain"
110
+ :valid: true
111
+ - :data: "gt 4000"
112
+ :valid: true
113
+ - :data: "range 2000 3333"
114
+ :valid: true
115
+ - :data: "eq isakmp"
116
+ :valid: false
117
+ :msg: "udp port-proto-name"
118
+ :udp_port_spec1:
119
+ - :data: ""
120
+ :valid: true
121
+ - :data: "eq 80"
122
+ :valid: true
123
+ - :data: "eq any"
124
+ :valid: false
125
+ :msg: "unknown port-prot-name"
126
+ - :data: "lt isakmp"
127
+ :valid: true
128
+ - :data: "gt ntp"
129
+ :valid: true
130
+ - :data: "range 53 443"
131
+ :valid: true
132
+ :udp_port_spec2:
133
+ - :data: ""
134
+ :valid: true
135
+ - :data: "eq 500"
136
+ :valid: true
137
+ - :data: "lt domain"
138
+ :valid: true
139
+ - :data: "gt 4000"
140
+ :valid: true
141
+ - :data: "range 2000 3333"
142
+ :valid: true
143
+ - :data: "eq pop3"
144
+ :valid: false
145
+ :msg: "tcp port-proto-name"
146
+ :ext_acl_log_spec:
147
+ - :data: ""
148
+ :valid: true
149
+ - :data: "log"
150
+ :valid: true
151
+ - :data: "log logcookie"
152
+ :valid: true
153
+ - :data: "log-input"
154
+ :valid: true
155
+ - :data: "log-input logcookie"
156
+ :valid: true
157
+ :tcp_flags:
158
+ - :data: ''
159
+ :valid: true
160
+ - :data: 'established'
161
+ :valid: true
162
+ - :data: 'syn fin ack'
163
+ :valid: true
164
+ - :data: 'acck established'
165
+ :valid: false
166
+ :tcp_flags2:
167
+ - :data: 'established'
168
+ :valid: true
169
+ - :data: 'established match-all +fin'
170
+ :valid: false
171
+ - :data: 'match-all +syn -fin -urg'
172
+ :valid: true
173
+ - :data: 'match-any -syn +fin +urg'
174
+ :valid: true
175
+ - :data: 'fin match-all +urg'
176
+ :valid: false
177
+ - :data: 'match-any -syn match-all -fin -urg'
178
+ :valid: false
179
+ - :data: 'match-any syn +fin'
180
+ :valid: false
181
+ :precedence:
182
+ - :data: ''
183
+ :valid: true
184
+ - :data: 'precedence 3'
185
+ :valid: true
186
+ - :data: 'precedence network'
187
+ :valid: true
188
+ :dscp:
189
+ - :data: ''
190
+ :valid: true
191
+ - :data: 'dscp af11'
192
+ :valid: true
193
+ - :data: 'dscp 6'
194
+ :valid: true
195
+ :tos:
196
+ - :data: ''
197
+ :valid: true
198
+ - :data: 'tos 10'
199
+ :valid: true
200
+ - :data: 'tos min-delay'
201
+ :valid: true
202
+ :time_range:
203
+ - :data: ''
204
+ :valid: true
205
+ - :data: 'time-range range_hoge'
206
+ :valid: true
@@ -0,0 +1,145 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'yaml'
3
+ require 'erb'
4
+
5
+ # data files
6
+ TOKEN_SEQ_FILE_LIST = [
7
+ 'stdacl_token_seq.yml',
8
+ 'extacl_token_seq.yml',
9
+ # 'extacl_objgrp_token_seq.yml'
10
+ ]
11
+
12
+ # return spec conf dir
13
+ def _spec_conf_dir(file)
14
+ specdir = Dir.new('./spec/conf/')
15
+ File.join(specdir.path, file)
16
+ end
17
+
18
+ # return spec data dir
19
+ def _spec_data_dir(file)
20
+ datadir = Dir.new('./spec/data/')
21
+ File.join(datadir.path, file)
22
+ end
23
+
24
+ def gen_testcase(tokens, fields)
25
+ if fields.empty?
26
+ [{ data: '', msg: '', valid: true }]
27
+ else
28
+ field = fields.shift
29
+ field_patterns = tokens[field.intern]
30
+ # generate testpatterns recursively.
31
+ leftover_results = gen_testcase(tokens, fields)
32
+ create_data(field_patterns, leftover_results)
33
+ end
34
+ end
35
+
36
+ def create_data(field_patterns, leftover_results)
37
+ field_patterns.reduce([]) do |curr_results, each|
38
+ leftover_results.each do |each_res|
39
+ ## do not add pattern that has multiple 'false'
40
+ ## add single fault pattern.
41
+ if each[:valid] || each_res[:valid]
42
+ curr_results.push(single_data(each, each_res))
43
+ end
44
+ end
45
+ curr_results
46
+ end
47
+ end
48
+
49
+ def single_data(curr, leftover)
50
+ {
51
+ data: [curr[:data], leftover[:data]].join(' '),
52
+ # used only single fail case,
53
+ # (1) curr AND leftover are VALID case
54
+ # (2) one of curr OR leftover is FALSE case
55
+ msg: curr[:msg] || leftover[:msg],
56
+ valid: curr[:valid] && leftover[:valid]
57
+ }
58
+ end
59
+
60
+ def each_test
61
+ TOKEN_SEQ_FILE_LIST.each do |each_file|
62
+ token_seq_data = YAML.load_file(_spec_conf_dir(each_file))
63
+ token_seq_data.each do |each|
64
+ puts "Test Name: #{each[:testname]}"
65
+ puts "Test Case File: #{each[:casedata]}"
66
+ yield(each)
67
+ end
68
+ end
69
+ end
70
+
71
+ ##############################
72
+ # generate test case data file
73
+
74
+ puts '## generate test case data file'
75
+ each_test do |each|
76
+ # read tokens pattern data
77
+ tokens = YAML.load_file(_spec_conf_dir(each[:casedata]))
78
+ # generate test case data
79
+ testcase_list = gen_testcase(tokens, each[:fieldseq])
80
+
81
+ # write datafile
82
+ case_file_base = [each[:testname], '.yml'].join
83
+ puts "Test Case Data: #{case_file_base}"
84
+ case_file = _spec_data_dir(case_file_base)
85
+ File.open(case_file, 'w') do |file|
86
+ file.puts YAML.dump(testcase_list.flatten)
87
+ end
88
+ end
89
+
90
+ ##############################
91
+ # run test per test case file
92
+
93
+ code_data = DATA.read
94
+ puts '## generate spec code'
95
+ each_test do |each|
96
+ spec_file_base = each[:testname] + '.rb'
97
+ puts "Spec code Data: #{spec_file_base}"
98
+ File.open(_spec_data_dir(spec_file_base), 'w') do |file|
99
+ code_erb = ERB.new(code_data, nil, '-')
100
+ file.puts code_erb.result(binding)
101
+ end
102
+ end
103
+
104
+ __END__
105
+ # -*- coding: utf-8 -*-
106
+ require 'spec_helper'
107
+ require 'stringio'
108
+
109
+ describe 'Parser' do
110
+ describe '#parse_file' do
111
+ before do
112
+ @parser = CiscoAclIntp::Parser.new(color: false, silent: true)
113
+ end
114
+
115
+ <%-
116
+ tests = YAML.load_file(_spec_data_dir(each[:testname] + '.yml'))
117
+ test_total = tests.length
118
+ test_curr = 1
119
+
120
+ tests.each do |t|
121
+ now = sprintf(
122
+ "%d/%.1f\%", test_curr, (100.0 * test_curr / test_total)
123
+ )
124
+ if t[:valid]
125
+ -%>
126
+ it 'should be parsed acl [<%= now %>]: <%= t[:data] %>' do
127
+ datastr = StringIO.new('<%= t[:data] %>', 'r')
128
+ @parser.parse_file(datastr)
129
+ @parser.contains_error?.should be_false
130
+ end
131
+ <%-
132
+ else
133
+ -%>
134
+ it 'should not be parsed acl [<%= now %>]: <%= t[:data] %>' do
135
+ datastr = StringIO.new('<%= t[:data] %>', 'r')
136
+ @parser.parse_file(datastr)
137
+ @parser.contains_error?.should be_true
138
+ end
139
+ <%-
140
+ end
141
+ test_curr = test_curr + 1
142
+ end
143
+ -%>
144
+ end # describe parse_file
145
+ end # describe Parser
@@ -0,0 +1,54 @@
1
+ # -*- coding: utf-8 -*-
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ require 'simplecov'
5
+ SimpleCov.start do
6
+ add_group 'Models', 'lib/'
7
+ end
8
+
9
+ require 'cisco_acl_intp'
10
+
11
+ include CiscoAclIntp
12
+ AclContainerBase.disable_color
13
+
14
+ RSpec::Matchers.define :be_aclstr do | expected_str |
15
+ match do | actual_str |
16
+ a = actual_str.strip
17
+ b = expected_str.strip
18
+ a.split(/\s+/) == b.split(/[\s\r\n]+/)
19
+ ## by this method, whitespaces are skipped.
20
+ ## because, it cannot handle correctly like 'remark foo -- bar'
21
+ end
22
+ end
23
+
24
+ # hash to hash-code-string
25
+ def _pph(hash)
26
+ kv = []
27
+ hash.each do | k, v |
28
+ case v
29
+ when String
30
+ kv.push %Q{:#{k.to_s}=>"#{v.to_s}"}
31
+ else
32
+ kv.push %Q{:#{k.to_s}=>#{v.to_s}}
33
+ end
34
+ end
35
+ kv.join(',')
36
+ end
37
+
38
+ # return specdir
39
+ def _spec_dir(file)
40
+ specdir = Dir.new('./spec/cisco_acl_intp/')
41
+ File.join(specdir.path, file)
42
+ end
43
+
44
+ # return test config/data dir
45
+ def _spec_conf_dir(file)
46
+ specdir = Dir.new('./spec/conf/')
47
+ File.join(specdir.path, file)
48
+ end
49
+
50
+ # return spec_data dir
51
+ def _spec_data_dir(file)
52
+ datadir = Dir.new('./spec/data/')
53
+ File.join(datadir.path, file)
54
+ end
@@ -0,0 +1,48 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ require 'optparse'
4
+ require 'cisco_acl_intp'
5
+
6
+ opts = {}
7
+ OptionParser.new do | each |
8
+ each.banner = "ruby #{$PROGRAM_NAME} [options] [args]"
9
+ each.on('-c', '--color', 'enable coloring') do |x|
10
+ opts[:color] = x
11
+ end
12
+ each.on('-d', '--debug', 'enable debug print') do |x|
13
+ opts[:debug] = x
14
+ end
15
+ each.on('--yydebug', 'enable yydebug') do |x|
16
+ opts[:yydebug] = x
17
+ end
18
+ each.on('-f FILE', '--file', 'acl file') do |x|
19
+ opts[:file] = x
20
+ end
21
+ begin
22
+ each.parse!
23
+ rescue
24
+ puts 'invalid option.'
25
+ puts each
26
+ end
27
+ end
28
+
29
+ popts = {}
30
+ popts[:color] = opts[:color] || false
31
+ popts[:debug] = opts[:debug] || false
32
+ popts[:yydebug] = opts[:yydebug] || false
33
+
34
+ parser = CiscoAclIntp::Parser.new(popts)
35
+
36
+ # read acl from file or STDIN
37
+ if opts[:file]
38
+ parser.parse_file opts[:file]
39
+ else
40
+ parser.parse_file $stdin
41
+ end
42
+
43
+ # print acl data
44
+ aclt = parser.acl_table
45
+ aclt.each do |name, acl|
46
+ puts "acl name : #{name}"
47
+ puts acl.to_s
48
+ end