cisco_acl_intp 0.0.2 → 0.0.3
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 +4 -4
- data/Gemfile +1 -1
- data/README.md +64 -3
- data/cisco_acl_intp.gemspec +2 -2
- data/lib/cisco_acl_intp/ace.rb +9 -286
- data/lib/cisco_acl_intp/ace_ip.rb +24 -22
- data/lib/cisco_acl_intp/ace_other_qualifiers.rb +23 -6
- data/lib/cisco_acl_intp/ace_port.rb +37 -182
- data/lib/cisco_acl_intp/ace_port_opr.rb +251 -0
- data/lib/cisco_acl_intp/ace_port_opr_base.rb +138 -0
- data/lib/cisco_acl_intp/ace_proto.rb +133 -328
- data/lib/cisco_acl_intp/ace_proto_base.rb +163 -0
- data/lib/cisco_acl_intp/ace_srcdst.rb +30 -40
- data/lib/cisco_acl_intp/ace_tcp_flags.rb +9 -3
- data/lib/cisco_acl_intp/acl.rb +1 -251
- data/lib/cisco_acl_intp/acl_base.rb +1 -1
- data/lib/cisco_acl_intp/acl_utils.rb +120 -0
- data/lib/cisco_acl_intp/extended_ace.rb +149 -0
- data/lib/cisco_acl_intp/mono_function_acl.rb +161 -0
- data/lib/cisco_acl_intp/parser.rb +237 -395
- data/lib/cisco_acl_intp/parser.ry +85 -243
- data/lib/cisco_acl_intp/parser_api.rb +2 -2
- data/lib/cisco_acl_intp/single_acl_base.rb +137 -0
- data/lib/cisco_acl_intp/standard_ace.rb +105 -0
- data/lib/cisco_acl_intp/version.rb +1 -1
- data/spec/cisco_acl_intp/ace_ip_spec.rb +63 -0
- data/spec/cisco_acl_intp/ace_other_qualifier_spec.rb +52 -1
- data/spec/cisco_acl_intp/ace_port_operator_spec.rb +340 -0
- data/spec/cisco_acl_intp/ace_port_spec.rb +67 -217
- data/spec/cisco_acl_intp/ace_proto_spec.rb +118 -41
- data/spec/cisco_acl_intp/ace_spec.rb +38 -547
- data/spec/cisco_acl_intp/ace_srcdst_spec.rb +115 -226
- data/spec/cisco_acl_intp/ace_tcp_flags_spec.rb +36 -4
- data/spec/cisco_acl_intp/acl_base_spec.rb +2 -2
- data/spec/cisco_acl_intp/extended_ace_spec.rb +411 -0
- data/spec/cisco_acl_intp/extended_acl_spec.rb +265 -0
- data/spec/cisco_acl_intp/scanner_spec.rb +13 -12
- data/spec/cisco_acl_intp/standard_ace_spec.rb +77 -0
- data/spec/cisco_acl_intp/standard_acl_spec.rb +245 -0
- data/spec/conf/scanner_spec_data.yml +32 -0
- data/spec/spec_helper.rb +2 -2
- metadata +20 -4
- data/spec/cisco_acl_intp/acl_spec.rb +0 -525
@@ -1,400 +1,205 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
|
3
|
-
require 'cisco_acl_intp/acl_base'
|
2
|
+
require 'cisco_acl_intp/ace_proto_base'
|
4
3
|
|
5
4
|
module CiscoAclIntp
|
6
|
-
# IP/TCP/UDP port number and protocol name container base
|
7
|
-
class AceProtoSpecBase < AclContainerBase
|
8
|
-
include Comparable
|
9
|
-
|
10
|
-
# @param [String] value Protocol name,
|
11
|
-
# it is literal used in Cisco IOS access-list
|
12
|
-
# @return [String]
|
13
|
-
attr_accessor :name
|
14
|
-
|
15
|
-
# @param [Integer] value Protocol/Port number
|
16
|
-
# @return [Integer]
|
17
|
-
attr_accessor :number
|
18
|
-
|
19
|
-
# @return [String, Symbol] L3/L4 protocol type
|
20
|
-
attr_reader :protocol
|
21
|
-
|
22
|
-
# Constructor
|
23
|
-
# @param [Hash] opts Options
|
24
|
-
# @option opts [String] :name Protocol name
|
25
|
-
# @option opts [Integer] :number Protocol/Port number
|
26
|
-
# @raise [AclArgumentError]
|
27
|
-
# @return [AceProtoSpecBase]
|
28
|
-
# @abstract
|
29
|
-
# @note Variable '@protocol'
|
30
|
-
# should be assigned in inherited class constructor,
|
31
|
-
# at first. (before call super class constructor)
|
32
|
-
def initialize(opts)
|
33
|
-
@options = opts
|
34
|
-
define_values
|
35
|
-
# (*1),(*3): check when @number exists
|
36
|
-
validate_protocol_number
|
37
|
-
# (*1)-(*4)
|
38
|
-
validate_protocol_name_and_number
|
39
|
-
end
|
40
|
-
|
41
|
-
# Check the port number in valid range of port number
|
42
|
-
# @abstract
|
43
|
-
# @return [Boolean]
|
44
|
-
def valid_range?
|
45
|
-
@number.integer?
|
46
|
-
end
|
47
|
-
|
48
|
-
# Generate string for Cisco IOS access list
|
49
|
-
# @return [String]
|
50
|
-
def to_s
|
51
|
-
@name || number_to_name
|
52
|
-
end
|
53
|
-
|
54
|
-
# Return protocol/port number
|
55
|
-
# @return [Integer] Protocol/Port number
|
56
|
-
def to_i
|
57
|
-
@number.to_i
|
58
|
-
end
|
59
|
-
|
60
|
-
# Convert protocol/port number to string (its name)
|
61
|
-
# @abstract
|
62
|
-
# @return [String] Name of protocol/port number.
|
63
|
-
# If does not match the number in IOS proto/port literal,
|
64
|
-
# return number.to_s string
|
65
|
-
def number_to_name
|
66
|
-
@number.to_s
|
67
|
-
end
|
68
|
-
|
69
|
-
# Convert protocol/port name to number
|
70
|
-
# @abstract
|
71
|
-
# @raise [AclArgumentError]
|
72
|
-
def name_to_number
|
73
|
-
fail AclArgumentError, 'abstract method: name_to_number called'
|
74
|
-
end
|
75
|
-
|
76
|
-
# Compare by port number
|
77
|
-
# @note Using "Comparable" module, '==' operator is defined by
|
78
|
-
# '<=>' operator. But '==' is overriden to compare instance
|
79
|
-
# equivalence instead of port number comparison.
|
80
|
-
# @param [AceProtoSpecBase] other Compared instance
|
81
|
-
# @return [Fixnum] Compare with protocol/port number
|
82
|
-
def <=>(other)
|
83
|
-
@number <=> other.to_i
|
84
|
-
end
|
85
|
-
|
86
|
-
# @return [Boolean] Compare with protocol/port number
|
87
|
-
def ==(other)
|
88
|
-
@protocol == other.protocol &&
|
89
|
-
@name == other.name &&
|
90
|
-
@number == other.number
|
91
|
-
end
|
92
|
-
|
93
|
-
private
|
94
|
-
|
95
|
-
# arguments |
|
96
|
-
# :name :number | @name @number
|
97
|
-
# --------------+----------------------------
|
98
|
-
# set set | use arg use arg (*1)
|
99
|
-
# none | use arg nil (*2)
|
100
|
-
# none set | nil use arg (*3)
|
101
|
-
# none | [ raise error ] (*4)
|
102
|
-
#
|
103
|
-
# (*1) args are set in parser (assume correct args)
|
104
|
-
# check if :name and number_to_name are same.
|
105
|
-
# (*2) args are set in parser (assume correct args)
|
106
|
-
# (*3)
|
107
|
-
|
108
|
-
# argment check: case (*1)
|
109
|
-
# @return [Boolean]
|
110
|
-
def arg_name_and_number_exists
|
111
|
-
@name && @number
|
112
|
-
end
|
113
|
-
|
114
|
-
# argment check: case (*2)
|
115
|
-
# @return [Boolean]
|
116
|
-
def arg_name_exists
|
117
|
-
@name && (!@number)
|
118
|
-
end
|
119
|
-
|
120
|
-
# argment check: case (*3)
|
121
|
-
# @return [Boolean]
|
122
|
-
def arg_number_exists
|
123
|
-
(!@name) && @number
|
124
|
-
end
|
125
|
-
|
126
|
-
# argment check: case (*4)
|
127
|
-
# @return [Boolean]
|
128
|
-
def arg_name_and_number_lost
|
129
|
-
(!@name) && (!@number)
|
130
|
-
end
|
131
|
-
|
132
|
-
# Set instance variables with ip/default-netmask
|
133
|
-
def define_values
|
134
|
-
@protocol = nil unless @protocol
|
135
|
-
@name = @options[:name] || nil
|
136
|
-
@number = @options[:number] || nil
|
137
|
-
end
|
138
|
-
|
139
|
-
# Validate protocol number
|
140
|
-
# @raise [AclArgumentError]
|
141
|
-
def validate_protocol_number
|
142
|
-
if @number
|
143
|
-
@number = (@number.instance_of?(String) ? @number.to_i : @number)
|
144
|
-
unless valid_range?
|
145
|
-
# Pattern (*1)(*3)
|
146
|
-
fail AclArgumentError, "Wrong protocol number: #{@number}"
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
# Validate protocol name and number (combination)
|
152
|
-
# @raise [AclArgumentError]
|
153
|
-
def validate_protocol_name_and_number
|
154
|
-
case
|
155
|
-
when arg_name_and_number_exists
|
156
|
-
# Case (*1): check parameter match
|
157
|
-
if @name != number_to_name
|
158
|
-
fail AclArgumentError, 'Specified protocol name and number not match'
|
159
|
-
end
|
160
|
-
when arg_name_exists
|
161
|
-
# Case (*2): try to convert from name to number
|
162
|
-
@number = name_to_number
|
163
|
-
when arg_number_exists
|
164
|
-
# Case (*3): try to convert from number to name
|
165
|
-
@name = number_to_name
|
166
|
-
when arg_name_and_number_lost
|
167
|
-
# Case (*4): raise error
|
168
|
-
fail AclArgumentError, 'Not specified protocol name and number'
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
5
|
# IP protocol number/name container
|
174
6
|
class AceIpProtoSpec < AceProtoSpecBase
|
175
|
-
#
|
176
|
-
MIN_PORT = 0
|
177
|
-
# Maximum port/protocol number
|
178
|
-
MAX_PORT = 255
|
179
|
-
|
180
|
-
# convert table of tcp port/name
|
7
|
+
# Convert table of tcp port/name
|
181
8
|
# @note protol='ip' means ANY ip protocol in Cisco IOS ACL.
|
182
9
|
# not defined 'ip' in IANA,
|
183
10
|
# http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
11
|
+
IP_PROTO_TABLE = {
|
12
|
+
'ahp' => 51,
|
13
|
+
'eigrp' => 88,
|
14
|
+
'esp' => 50,
|
15
|
+
'gre' => 47,
|
16
|
+
'igmp' => 2,
|
17
|
+
'igrp' => 9,
|
18
|
+
'ipinip' => 94,
|
19
|
+
'nos' => 4,
|
20
|
+
'ospf' => 89,
|
21
|
+
'pcp' => 108,
|
22
|
+
'pim' => 103,
|
23
|
+
'icmp' => 1,
|
24
|
+
'tcp' => 6,
|
25
|
+
'udp' => 17,
|
26
|
+
'ip' => -1 # dummy
|
200
27
|
}
|
201
28
|
|
202
29
|
# Constructor
|
203
|
-
# @param [
|
30
|
+
# @param [String, Integer] proto_id L3 Protocol ID (No. or Name)
|
204
31
|
# @return [AceIpProtoSpec]
|
205
|
-
def initialize(
|
32
|
+
def initialize(proto_id = nil)
|
33
|
+
super(proto_id, 255)
|
206
34
|
@protocol = :ip
|
207
|
-
super
|
208
35
|
end
|
209
36
|
|
210
|
-
#
|
211
|
-
# @return [
|
212
|
-
def
|
213
|
-
|
37
|
+
# Protocol Table
|
38
|
+
# @return [Hash] Protocol table
|
39
|
+
def proto_table
|
40
|
+
IP_PROTO_TABLE
|
214
41
|
end
|
215
42
|
|
216
43
|
# Check the port name is known or not.
|
217
44
|
# @param [String] name IP/TCP/UDP port/protocol name
|
218
45
|
# @return [Boolean]
|
219
46
|
def self.valid_name?(name)
|
220
|
-
|
47
|
+
IP_PROTO_TABLE.key?(name)
|
221
48
|
end
|
222
49
|
|
223
|
-
#
|
224
|
-
# @return [
|
225
|
-
def
|
226
|
-
|
50
|
+
# check protocol is 'ip'?
|
51
|
+
# @return [Boolean]
|
52
|
+
def ip?
|
53
|
+
@name == 'ip'
|
227
54
|
end
|
228
55
|
|
229
|
-
#
|
230
|
-
# @return [
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
56
|
+
# check protocol is 'tcp'?
|
57
|
+
# @return [Boolean]
|
58
|
+
def tcp?
|
59
|
+
@name == 'tcp'
|
60
|
+
end
|
61
|
+
|
62
|
+
# check protocol is 'udp'?
|
63
|
+
# @return [Boolean]
|
64
|
+
def udp?
|
65
|
+
@name == 'udp'
|
66
|
+
end
|
67
|
+
|
68
|
+
# Protocol inclusion relation
|
69
|
+
# @param [AceIpProtoSpec] other Other protocol spec
|
70
|
+
def contains?(other)
|
71
|
+
if ip?
|
72
|
+
other.ip? || other.tcp? || other.udp?
|
235
73
|
else
|
236
|
-
|
74
|
+
self == other
|
237
75
|
end
|
238
76
|
end
|
239
77
|
end
|
240
78
|
|
241
79
|
# TCP/UDP port range validation feature
|
242
80
|
class AceTcpUdpProtoSpec < AceProtoSpecBase
|
243
|
-
# Minimum port/protocol number
|
244
|
-
MIN_PORT = 0
|
245
|
-
# Maximum port/protocol number
|
246
|
-
MAX_PORT = 65_535
|
247
|
-
|
248
81
|
# Constructor
|
249
|
-
# @param [
|
82
|
+
# @param [String, Integer] proto_id Protocol ID (No. or Name)
|
250
83
|
# @return [AceTcpProtoSpec]
|
251
|
-
def initialize(
|
84
|
+
def initialize(proto_id = nil)
|
85
|
+
super(proto_id, 65_535)
|
252
86
|
@protocol = :tcp_udp
|
253
|
-
super
|
254
|
-
end
|
255
|
-
|
256
|
-
# Check the port number in valid range of port number
|
257
|
-
# @return [Boolean]
|
258
|
-
def valid_range?
|
259
|
-
(MIN_PORT .. MAX_PORT).include?(@number)
|
260
87
|
end
|
261
88
|
end
|
262
89
|
|
263
90
|
# TCP protocol number/name container
|
264
91
|
class AceTcpProtoSpec < AceTcpUdpProtoSpec
|
265
92
|
# convert table of tcp port/name
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
93
|
+
TCP_PROTO_TABLE = {
|
94
|
+
'bgp' => 179,
|
95
|
+
'chargen' => 19,
|
96
|
+
'cmd' => 514,
|
97
|
+
'daytime' => 13,
|
98
|
+
'discard' => 9,
|
99
|
+
'domain' => 53,
|
100
|
+
'drip' => 3949,
|
101
|
+
'echo' => 7,
|
102
|
+
'exec' => 512,
|
103
|
+
'finger' => 79,
|
104
|
+
'ftp' => 21,
|
105
|
+
'ftp-data' => 20,
|
106
|
+
'gopher' => 70,
|
107
|
+
'hostname' => 101,
|
108
|
+
'ident' => 113,
|
109
|
+
'irc' => 194,
|
110
|
+
'klogin' => 543,
|
111
|
+
'kshell' => 544,
|
112
|
+
'login' => 513,
|
113
|
+
'lpd' => 515,
|
114
|
+
'nntp' => 119,
|
115
|
+
'pim-auto-rp' => 496,
|
116
|
+
'pop2' => 109,
|
117
|
+
'pop3' => 110,
|
118
|
+
'smtp' => 25,
|
119
|
+
'sunrpc' => 111,
|
120
|
+
'tacacs' => 49,
|
121
|
+
'talk' => 517,
|
122
|
+
'telnet' => 23,
|
123
|
+
'time' => 37,
|
124
|
+
'uucp' => 540,
|
125
|
+
'whois' => 43,
|
126
|
+
'www' => 80
|
300
127
|
}
|
301
128
|
|
302
129
|
# Constructor
|
303
|
-
# @param [
|
130
|
+
# @param [String, Integer] proto_id Protocol ID (No. or Name)
|
304
131
|
# @return [AceTcpProtoSpec]
|
305
|
-
def initialize(
|
306
|
-
@protocol = :tcp
|
132
|
+
def initialize(proto_id = nil)
|
307
133
|
super
|
134
|
+
@protocol = :tcp
|
135
|
+
end
|
136
|
+
|
137
|
+
# Protocol Table
|
138
|
+
# @return [Hash] Protocol table
|
139
|
+
def proto_table
|
140
|
+
TCP_PROTO_TABLE
|
308
141
|
end
|
309
142
|
|
310
143
|
# Check the port name is known or not.
|
311
144
|
# @param [String] name IP/TCP/UDP port/protocol name
|
312
145
|
# @return [Boolean]
|
313
146
|
def self.valid_name?(name)
|
314
|
-
|
315
|
-
end
|
316
|
-
|
317
|
-
# Convert protocol to port number by string (its name)
|
318
|
-
# @return [String] Name of protocol/port number.
|
319
|
-
def number_to_name
|
320
|
-
TCP_PORT_NAME_TABLE[@number] || @number.to_s
|
321
|
-
end
|
322
|
-
|
323
|
-
# Convert protocol/port name to number
|
324
|
-
# @return [String] Number of protocol/port name
|
325
|
-
# @raise [AclArgumentError]
|
326
|
-
def name_to_number
|
327
|
-
if TCP_PORT_NAME_TABLE.value?(@name)
|
328
|
-
TCP_PORT_NAME_TABLE.invert[@name]
|
329
|
-
else
|
330
|
-
fail AclArgumentError, "Unknown tcp port name: #{@name}"
|
331
|
-
end
|
147
|
+
TCP_PROTO_TABLE.key?(name)
|
332
148
|
end
|
333
149
|
end
|
334
150
|
|
335
151
|
# UDP protocol number/name container
|
336
152
|
class AceUdpProtoSpec < AceTcpUdpProtoSpec
|
337
153
|
# convert table of UDP port/name
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
154
|
+
UDP_PROTO_TABLE = {
|
155
|
+
'biff' => 512,
|
156
|
+
'bootpc' => 68,
|
157
|
+
'bootps' => 67,
|
158
|
+
'discard' => 9,
|
159
|
+
'dnsix' => 195,
|
160
|
+
'domain' => 53,
|
161
|
+
'echo' => 7,
|
162
|
+
'isakmp' => 500,
|
163
|
+
'mobile-ip' => 434,
|
164
|
+
'nameserver' => 42,
|
165
|
+
'netbios-dgm' => 138,
|
166
|
+
'netbios-ns' => 137,
|
167
|
+
'netbios-ss' => 139,
|
168
|
+
'non500-isakmp' => 4500,
|
169
|
+
'ntp' => 123,
|
170
|
+
'pim-auto-rp' => 496,
|
171
|
+
'rip' => 520,
|
172
|
+
'snmp' => 161,
|
173
|
+
'snmptrap' => 162,
|
174
|
+
'sunrpc' => 111,
|
175
|
+
'syslog' => 514,
|
176
|
+
'tacacs' => 49,
|
177
|
+
'talk' => 517,
|
178
|
+
'tftp' => 69,
|
179
|
+
'time' => 37,
|
180
|
+
'who' => 513,
|
181
|
+
'xdmcp' => 177
|
366
182
|
}
|
367
183
|
|
368
184
|
# Constructor
|
369
|
-
# @param [
|
185
|
+
# @param [String, Integer] proto_id Protocol ID (No. or Name)
|
370
186
|
# @return [AceUdpProtoSpec]
|
371
|
-
def initialize(
|
372
|
-
@protocol = :udp
|
187
|
+
def initialize(proto_id = nil)
|
373
188
|
super
|
189
|
+
@protocol = :udp
|
190
|
+
end
|
191
|
+
|
192
|
+
# Protocol Table
|
193
|
+
# @return [Hash] Protocol table
|
194
|
+
def proto_table
|
195
|
+
UDP_PROTO_TABLE
|
374
196
|
end
|
375
197
|
|
376
198
|
# Check the port name is known or not.
|
377
199
|
# @param [String] name IP/TCP/UDP port/protocol name
|
378
200
|
# @return [Boolean]
|
379
201
|
def self.valid_name?(name)
|
380
|
-
|
381
|
-
end
|
382
|
-
|
383
|
-
# Convert protocol/port number to string (its name)
|
384
|
-
# @return [String] Name of protocol/port number.
|
385
|
-
def number_to_name
|
386
|
-
UDP_PORT_NAME_TABLE[@number] || @number.to_s
|
387
|
-
end
|
388
|
-
|
389
|
-
# Convert protocol/port name to number
|
390
|
-
# @return [String] Number of protocol/port name
|
391
|
-
# @raise [AclArgumentError]
|
392
|
-
def name_to_number
|
393
|
-
if UDP_PORT_NAME_TABLE.value?(@name)
|
394
|
-
UDP_PORT_NAME_TABLE.invert[@name]
|
395
|
-
else
|
396
|
-
fail AclArgumentError, "Unknown udp port name: #{@name}"
|
397
|
-
end
|
202
|
+
UDP_PROTO_TABLE.key?(name)
|
398
203
|
end
|
399
204
|
end
|
400
205
|
end # module
|
@@ -0,0 +1,163 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'cisco_acl_intp/acl_base'
|
3
|
+
|
4
|
+
module CiscoAclIntp
|
5
|
+
# IP/TCP/UDP protocol number and protocol name container base
|
6
|
+
class AceProtoSpecBase < AclContainerBase
|
7
|
+
include Comparable
|
8
|
+
|
9
|
+
# @return [String] Protocol name
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
# @return [Integer] Protocol/Port number
|
13
|
+
attr_reader :number
|
14
|
+
|
15
|
+
# @return [Integer] Maximum protocol/port number
|
16
|
+
attr_reader :max_num
|
17
|
+
|
18
|
+
# @return [Symbol] L3/L4 protocol type
|
19
|
+
attr_reader :protocol
|
20
|
+
|
21
|
+
# Convert table of protocol number/name
|
22
|
+
# @note Keys(protocol names) are String not as Symbol,
|
23
|
+
# because there are keys exists including '-'.
|
24
|
+
DUMMY_PROTO_TABLE = {
|
25
|
+
'any' => -1 # dummy
|
26
|
+
}
|
27
|
+
|
28
|
+
# Protocol Table
|
29
|
+
# @return [Hash] Protocol table
|
30
|
+
# @abstract
|
31
|
+
def proto_table
|
32
|
+
DUMMY_PROTO_TABLE
|
33
|
+
end
|
34
|
+
|
35
|
+
# Constructor
|
36
|
+
# @param [String, Integer] proto_id Protocol ID (No. or Name)
|
37
|
+
# @param [Integer] max_num Maximum protocol number.
|
38
|
+
# @raise [AclArgumentError]
|
39
|
+
# @return [AceProtoSpecBase]
|
40
|
+
# @abstract
|
41
|
+
# @note Variable '@protocol'
|
42
|
+
# should be assigned in inherited class constructor.
|
43
|
+
def initialize(proto_id = nil, max_num = 255)
|
44
|
+
@protocol = nil # must be defined in inherited class.
|
45
|
+
@max_num = max_num
|
46
|
+
|
47
|
+
case proto_id
|
48
|
+
when /\d+/ # Integer-String, MUST check before 'String'
|
49
|
+
define_param_by_integer(proto_id.to_i)
|
50
|
+
when String # Not Integer-String
|
51
|
+
define_param_by_string(proto_id)
|
52
|
+
when Integer
|
53
|
+
define_param_by_integer(proto_id)
|
54
|
+
else
|
55
|
+
fail AclArgumentError, "invalid protocol id #{proto_id}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Check the port number in valid range of port number
|
60
|
+
# @return [Boolean]
|
61
|
+
def valid_range?
|
62
|
+
(0 .. @max_num).include?(@number)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Check the port name is known or not.
|
66
|
+
# @param [String] name IP/TCP/UDP port/protocol name
|
67
|
+
# @return [Boolean]
|
68
|
+
def valid_name?
|
69
|
+
proto_table.key?(@name)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Generate string for Cisco IOS access list
|
73
|
+
# @return [String]
|
74
|
+
def to_s
|
75
|
+
@name
|
76
|
+
end
|
77
|
+
|
78
|
+
# Return protocol/port number
|
79
|
+
# @return [Integer] Protocol/Port number
|
80
|
+
def to_i
|
81
|
+
@number.to_i
|
82
|
+
end
|
83
|
+
|
84
|
+
# Compare by port number
|
85
|
+
# @note Using "Comparable" module, '==' operator is defined by
|
86
|
+
# '<=>' operator. But '==' is overriden to compare instance
|
87
|
+
# equivalence instead of port number comparison.
|
88
|
+
# @param [AceProtoSpecBase] other Compared instance
|
89
|
+
# @return [Fixnum] Compare with protocol/port number
|
90
|
+
def <=>(other)
|
91
|
+
@number <=> other.to_i
|
92
|
+
end
|
93
|
+
|
94
|
+
# Check equality
|
95
|
+
# @param [AceProtoSpecBase] other RHS object.
|
96
|
+
# @return [Boolean] Compare with protocol/port number
|
97
|
+
def ==(other)
|
98
|
+
@protocol == other.protocol &&
|
99
|
+
@name == other.name &&
|
100
|
+
@number == other.number
|
101
|
+
end
|
102
|
+
|
103
|
+
# Check if port/protocol number is minimum.
|
104
|
+
# @return [Boolean]
|
105
|
+
def min?
|
106
|
+
@number == 0
|
107
|
+
end
|
108
|
+
|
109
|
+
# Check if port/protocol number is maximum.
|
110
|
+
# @return [Boolean]
|
111
|
+
def max?
|
112
|
+
@number == @max_num
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
# Convert protocol/port number to string (its name)
|
118
|
+
# @return [String] Name of protocol/port number.
|
119
|
+
# If does not match the number in IOS proto/port literal,
|
120
|
+
# return number.to_s string
|
121
|
+
def number_to_name
|
122
|
+
proto_table.invert[@number] || @number.to_s
|
123
|
+
end
|
124
|
+
|
125
|
+
# Convert protocol/port name to number
|
126
|
+
# @raise [AclArgumentError]
|
127
|
+
def name_to_number
|
128
|
+
if proto_table.key?(@name)
|
129
|
+
proto_table[@name]
|
130
|
+
else
|
131
|
+
fail AclArgumentError, "Unknown protocol name: #{@name}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# @param [String] name Protocol name.
|
136
|
+
# @raise [AclArgumentError]
|
137
|
+
def define_param_by_string(name)
|
138
|
+
@name = name
|
139
|
+
if valid_name?
|
140
|
+
@number = name_to_number
|
141
|
+
else
|
142
|
+
fail AclArgumentError, "Unknown protocol name: #{@name}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# @param [Integer] number Protocol No.
|
147
|
+
# @raise [AclArgumentError]
|
148
|
+
def define_param_by_integer(number)
|
149
|
+
@number = number
|
150
|
+
if valid_range?
|
151
|
+
@name = number_to_name
|
152
|
+
else
|
153
|
+
fail AclArgumentError, "Invalid protocol number: #{@number}"
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end # module
|
158
|
+
|
159
|
+
### Local variables:
|
160
|
+
### mode: Ruby
|
161
|
+
### coding: utf-8-unix
|
162
|
+
### indent-tabs-mode: nil
|
163
|
+
### End:
|