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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +64 -3
  4. data/cisco_acl_intp.gemspec +2 -2
  5. data/lib/cisco_acl_intp/ace.rb +9 -286
  6. data/lib/cisco_acl_intp/ace_ip.rb +24 -22
  7. data/lib/cisco_acl_intp/ace_other_qualifiers.rb +23 -6
  8. data/lib/cisco_acl_intp/ace_port.rb +37 -182
  9. data/lib/cisco_acl_intp/ace_port_opr.rb +251 -0
  10. data/lib/cisco_acl_intp/ace_port_opr_base.rb +138 -0
  11. data/lib/cisco_acl_intp/ace_proto.rb +133 -328
  12. data/lib/cisco_acl_intp/ace_proto_base.rb +163 -0
  13. data/lib/cisco_acl_intp/ace_srcdst.rb +30 -40
  14. data/lib/cisco_acl_intp/ace_tcp_flags.rb +9 -3
  15. data/lib/cisco_acl_intp/acl.rb +1 -251
  16. data/lib/cisco_acl_intp/acl_base.rb +1 -1
  17. data/lib/cisco_acl_intp/acl_utils.rb +120 -0
  18. data/lib/cisco_acl_intp/extended_ace.rb +149 -0
  19. data/lib/cisco_acl_intp/mono_function_acl.rb +161 -0
  20. data/lib/cisco_acl_intp/parser.rb +237 -395
  21. data/lib/cisco_acl_intp/parser.ry +85 -243
  22. data/lib/cisco_acl_intp/parser_api.rb +2 -2
  23. data/lib/cisco_acl_intp/single_acl_base.rb +137 -0
  24. data/lib/cisco_acl_intp/standard_ace.rb +105 -0
  25. data/lib/cisco_acl_intp/version.rb +1 -1
  26. data/spec/cisco_acl_intp/ace_ip_spec.rb +63 -0
  27. data/spec/cisco_acl_intp/ace_other_qualifier_spec.rb +52 -1
  28. data/spec/cisco_acl_intp/ace_port_operator_spec.rb +340 -0
  29. data/spec/cisco_acl_intp/ace_port_spec.rb +67 -217
  30. data/spec/cisco_acl_intp/ace_proto_spec.rb +118 -41
  31. data/spec/cisco_acl_intp/ace_spec.rb +38 -547
  32. data/spec/cisco_acl_intp/ace_srcdst_spec.rb +115 -226
  33. data/spec/cisco_acl_intp/ace_tcp_flags_spec.rb +36 -4
  34. data/spec/cisco_acl_intp/acl_base_spec.rb +2 -2
  35. data/spec/cisco_acl_intp/extended_ace_spec.rb +411 -0
  36. data/spec/cisco_acl_intp/extended_acl_spec.rb +265 -0
  37. data/spec/cisco_acl_intp/scanner_spec.rb +13 -12
  38. data/spec/cisco_acl_intp/standard_ace_spec.rb +77 -0
  39. data/spec/cisco_acl_intp/standard_acl_spec.rb +245 -0
  40. data/spec/conf/scanner_spec_data.yml +32 -0
  41. data/spec/spec_helper.rb +2 -2
  42. metadata +20 -4
  43. 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
- # Minimum port/protocol number
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
- IP_PROTO_NAME_TABLE = {
185
- 51 => 'ahp',
186
- 88 => 'eigrp',
187
- 50 => 'esp',
188
- 47 => 'gre',
189
- 2 => 'igmp',
190
- 9 => 'igrp',
191
- 94 => 'ipinip',
192
- 4 => 'nos',
193
- 89 => 'ospf',
194
- 108 => 'pcp',
195
- 103 => 'pim',
196
- 1 => 'icmp',
197
- 6 => 'tcp',
198
- 17 => 'udp',
199
- -1 => 'ip' # dummy number
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 [Hash] opts Options of <AceProtoSpecBase>
30
+ # @param [String, Integer] proto_id L3 Protocol ID (No. or Name)
204
31
  # @return [AceIpProtoSpec]
205
- def initialize(opts)
32
+ def initialize(proto_id = nil)
33
+ super(proto_id, 255)
206
34
  @protocol = :ip
207
- super
208
35
  end
209
36
 
210
- # Check the port number in valid range of port number
211
- # @return [Boolean]
212
- def valid_range?
213
- (MIN_PORT .. MAX_PORT).include?(@number)
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
- IP_PROTO_NAME_TABLE.value?(name)
47
+ IP_PROTO_TABLE.key?(name)
221
48
  end
222
49
 
223
- # Convert protocol/port number to string (its name)
224
- # @return [String] Name of protocol/port number.
225
- def number_to_name
226
- IP_PROTO_NAME_TABLE[@number] || @number.to_s
50
+ # check protocol is 'ip'?
51
+ # @return [Boolean]
52
+ def ip?
53
+ @name == 'ip'
227
54
  end
228
55
 
229
- # Convert protocol/port name to number
230
- # @return [String] Number of protocol/port name
231
- # @raise [AclArgumentError]
232
- def name_to_number
233
- if IP_PROTO_NAME_TABLE.value?(@name)
234
- IP_PROTO_NAME_TABLE.invert[@name]
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
- fail AclArgumentError, "Unknown ip protocol name: #{@name}"
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 [Hash] opts Options of <AceProtoSpecBase>
82
+ # @param [String, Integer] proto_id Protocol ID (No. or Name)
250
83
  # @return [AceTcpProtoSpec]
251
- def initialize(opts)
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
- TCP_PORT_NAME_TABLE = {
267
- 179 => 'bgp',
268
- 19 => 'chargen',
269
- 514 => 'cmd',
270
- 13 => 'daytime',
271
- 9 => 'discard',
272
- 53 => 'domain',
273
- 3949 => 'drip',
274
- 7 => 'echo',
275
- 512 => 'exec',
276
- 79 => 'finger',
277
- 21 => 'ftp',
278
- 20 => 'ftp-data',
279
- 70 => 'gopher',
280
- 101 => 'hostname',
281
- 113 => 'ident',
282
- 194 => 'irc',
283
- 543 => 'klogin',
284
- 544 => 'kshell',
285
- 513 => 'login',
286
- 515 => 'lpd',
287
- 119 => 'nntp',
288
- 496 => 'pim-auto-rp',
289
- 109 => 'pop2',
290
- 110 => 'pop3',
291
- 25 => 'smtp',
292
- 111 => 'sunrpc',
293
- 49 => 'tacacs',
294
- 517 => 'talk',
295
- 23 => 'telnet',
296
- 37 => 'time',
297
- 540 => 'uucp',
298
- 43 => 'whois',
299
- 80 => 'www'
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 [Hash] opts Options of <AceProtoSpecBase>
130
+ # @param [String, Integer] proto_id Protocol ID (No. or Name)
304
131
  # @return [AceTcpProtoSpec]
305
- def initialize(opts)
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
- TCP_PORT_NAME_TABLE.value?(name)
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
- UDP_PORT_NAME_TABLE = {
339
- 512 => 'biff',
340
- 68 => 'bootpc',
341
- 67 => 'bootps',
342
- 9 => 'discard',
343
- 195 => 'dnsix',
344
- 53 => 'domain',
345
- 7 => 'echo',
346
- 500 => 'isakmp',
347
- 434 => 'mobile-ip',
348
- 42 => 'nameserver',
349
- 138 => 'netbios-dgm',
350
- 137 => 'netbios-ns',
351
- 139 => 'netbios-ss',
352
- 4500 => 'non500-isakmp',
353
- 123 => 'ntp',
354
- 496 => 'pim-auto-rp',
355
- 520 => 'rip',
356
- 161 => 'snmp',
357
- 162 => 'snmptrap',
358
- 111 => 'sunrpc',
359
- 514 => 'syslog',
360
- 49 => 'tacacs',
361
- 517 => 'talk',
362
- 69 => 'tftp',
363
- 37 => 'time',
364
- 513 => 'who',
365
- 177 => 'xdmcp'
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 [Hash] opts Options of <AceProtoSpecBase>
185
+ # @param [String, Integer] proto_id Protocol ID (No. or Name)
370
186
  # @return [AceUdpProtoSpec]
371
- def initialize(opts)
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
- UDP_PORT_NAME_TABLE.value?(name)
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: