cisco_acl_intp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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