ipaccess 1.2.0 → 1.2.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 (49) hide show
  1. checksums.yaml +5 -13
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.yardopts +2 -0
  5. data/ChangeLog +66 -0
  6. data/Manifest.txt +5 -10
  7. data/README.md +2 -2
  8. data/Rakefile +1 -1
  9. data/docs/HISTORY +11 -0
  10. data/docs/TODO +1 -1
  11. data/docs/yard-tpl/default/fulldoc/html/css/common.css +5 -0
  12. data/examples/open-uri.rb +14 -0
  13. data/examples/telnet.rb +1 -1
  14. data/ipaccess.gemspec +62 -0
  15. data/lib/ipaccess.rb +2 -566
  16. data/lib/ipaccess/arm_sockets.rb +0 -1
  17. data/lib/ipaccess/core.rb +523 -0
  18. data/lib/ipaccess/ghost_doc/ghost_doc.rb +1 -1
  19. data/lib/ipaccess/ghost_doc/ghost_doc_acl.rdoc +54 -0
  20. data/lib/ipaccess/ghost_doc/ghost_doc_net_ftp.rb +35 -19
  21. data/lib/ipaccess/ghost_doc/ghost_doc_net_http.rb +34 -18
  22. data/lib/ipaccess/ghost_doc/ghost_doc_net_smtp.rb +35 -19
  23. data/lib/ipaccess/ghost_doc/ghost_doc_net_telnet.rb +35 -19
  24. data/lib/ipaccess/ghost_doc/ghost_doc_patched_usage.rdoc +65 -0
  25. data/lib/ipaccess/ghost_doc/ghost_doc_sockets.rb +353 -125
  26. data/lib/ipaccess/ip_access_check.rb +2 -2
  27. data/lib/ipaccess/ip_access_errors.rb +2 -2
  28. data/lib/ipaccess/ip_access_list.rb +3 -3
  29. data/lib/ipaccess/patches/generic.rb +150 -183
  30. data/lib/ipaccess/patches/net_ftp.rb +1 -2
  31. data/lib/ipaccess/patches/net_http.rb +10 -14
  32. data/lib/ipaccess/patches/net_imap.rb +1 -2
  33. data/lib/ipaccess/patches/net_pop.rb +2 -4
  34. data/lib/ipaccess/patches/net_smtp.rb +2 -4
  35. data/lib/ipaccess/patches/net_telnet.rb +1 -2
  36. data/lib/ipaccess/patches/sockets.rb +67 -69
  37. data/lib/ipaccess/socket.rb +0 -17
  38. metadata +70 -100
  39. metadata.gz.sig +0 -0
  40. data/lib/ipaccess/ghost_doc/ghost_doc_acl.rb +0 -54
  41. data/lib/ipaccess/ghost_doc/ghost_doc_p_blacklist.rb +0 -36
  42. data/lib/ipaccess/ghost_doc/ghost_doc_p_blacklist_e.rb +0 -7
  43. data/lib/ipaccess/ghost_doc/ghost_doc_p_unblacklist.rb +0 -36
  44. data/lib/ipaccess/ghost_doc/ghost_doc_p_unblacklist_e.rb +0 -7
  45. data/lib/ipaccess/ghost_doc/ghost_doc_p_unwhitelist.rb +0 -36
  46. data/lib/ipaccess/ghost_doc/ghost_doc_p_unwhitelist_e.rb +0 -7
  47. data/lib/ipaccess/ghost_doc/ghost_doc_p_whitelist.rb +0 -36
  48. data/lib/ipaccess/ghost_doc/ghost_doc_p_whitelist_e.rb +0 -7
  49. data/lib/ipaccess/ghost_doc/ghost_doc_patched_usage.rb +0 -64
@@ -33,4 +33,3 @@ IPAccess.arm UDPSocket
33
33
  IPAccess.arm TCPSocket
34
34
  IPAccess.arm TCPServer
35
35
  IPAccess.arm SOCKSSocket if Object.const_defined?(:SOCKSSocket)
36
-
@@ -0,0 +1,523 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Author:: Paweł Wilk (mailto:pw@gnu.org)
4
+ # Copyright:: Copyright (c) 2009-2014 by Paweł Wilk
5
+ # License:: This program is licensed under the terms of {GNU Lesser General Public License}[link:docs/LGPL.html] or {Ruby License}[link:docs/COPYING.html].
6
+ #
7
+ # Classes contained in this library allow you to create
8
+ # and manage IP access lists in an easy way. You may use
9
+ # IPAccess::Set class to maintain inpu/output traffic control.
10
+ # You also may use IPAccess::List class directly to build
11
+ # your own access sets based on black lists and white lists.
12
+
13
+ require 'ipaccess/patches/netaddr'
14
+ require 'ipaccess/ip_access_list'
15
+ require 'ipaccess/ip_access_set'
16
+
17
+ # This module contains classes that are used to control IP access.
18
+ # There are three major components you may want to use:
19
+ #
20
+ # === IPAccess::List class
21
+ #
22
+ # This class lets you create IP access list with blacklisted
23
+ # and whitelisted elements. It also has methods for checking
24
+ # whether given IP matches the list.
25
+ #
26
+ # === IPAccess::Set class
27
+ #
28
+ # This class contains two objects that are instances
29
+ # of IPAccess::List class. It allows you to create so
30
+ # called access set. The access set contains members named
31
+ # +input+ and +output+. All methods that validate IP access do it
32
+ # against one of the lists. Input access list is for incomming
33
+ # and output for outgoing IP traffic. In case of connection-oriented
34
+ # sockets and other network objects the convention is to use output access
35
+ # list to validate connections that we initiate. The incomming traffic
36
+ # in that model means the connections initiated by a remote peer.
37
+ #
38
+ # === Patching engine
39
+ #
40
+ # IPAccess was initialy considered as a set of classes that you may use
41
+ # in your own programs to control IP access. That means your own classes
42
+ # used for communication should use access lists or sets before making any
43
+ # real connections or sending any datagrams.
44
+ #
45
+ # Fortunately there are many network classes, including sockets, that Ruby ships with.
46
+ # It would be waste of resources to not modify them to support IP access control
47
+ # and automagically throw exceptions when access should be denied.
48
+ #
49
+ # And here the special module method called +IPAccess.arm+
50
+ # comes in. It lets you patch most of Ruby's networking classes and objects. Besides
51
+ # equipping them in IPAccess::Set instance it also adds some methods for doing quick
52
+ # checks and changes in access lists.
53
+ #
54
+ # The patching engine can arm network classes and single network objects.
55
+ # It is not loaded by default since you may not want extra code attached to a
56
+ # program that uses access lists or sets with own access checking code.
57
+ #
58
+ # === Variants of popular classes
59
+ #
60
+ # Sometimes you want to write a code that uses standard Ruby's network objects
61
+ # but you find it dirty to alter classes or objects. In that case you may
62
+ # want to use static variants of Ruby's network classes that are not patches
63
+ # but derived classes.
64
+ #
65
+ # === Exceptions
66
+ #
67
+ # When you are dealing with patched (armed) versions of classes and objects
68
+ # or when you are using special variants of popular network classes, you have
69
+ # to rely on exceptions as the only way for access checking methods to tell
70
+ # your program that an event (like access denied) happened.
71
+ #
72
+ # Note that when exception is thrown the communication session is closed in case
73
+ # of connection-oriented network objects. You may change it by setting
74
+ # +opened_on_deny+ attribute to +true+.
75
+ #
76
+ # See IPAccess::Set#check_in to know more about tracking original network object
77
+ # that caused exception to happend. Note that in case of armed versions of network
78
+ # classes (or access-contolled variants) an information about original network
79
+ # object stored within an exception will be set to +nil+ if access had been denied before
80
+ # object was initialized. This shouldn't happend often, since access checks are lazy
81
+ # (they are performed only when connection is going to be made).
82
+ #
83
+ # See IPAccessDenied for more information about what you can do with exceptions.
84
+ #
85
+ # === Sockets in armed network objects
86
+ #
87
+ # Specialized Ruby's network classes, such as Net::HTTP or Net::Telnet
88
+ # and their variants created by this library, make use of socket objects.
89
+ # For example Net::HTTP class uses TCPSocket instance to
90
+ # create TCP connection. When versions of these <tt>Net::</tt> objects with
91
+ # enabled access control are used then the internal routines of IPAccess
92
+ # will also try to patch underlying sockets and assign to them the same
93
+ # access set that is used by main object. It is done to avoid access leaks.
94
+ # However, such armed internal sockets will have +opened_on_deny+ flag switched on
95
+ # since closing session (and an eventual connection) should be settled by main object.
96
+ #
97
+ # === Ordination of elements
98
+ #
99
+ # To properly understand what are the most important structures mentioned above it's worth
100
+ # to look at the diagram:
101
+ #
102
+ # link:images/ipaccess_view.png
103
+ #
104
+ # == Usage
105
+ #
106
+ # === Handling access sets and access lists
107
+ #
108
+ # If you need just IP access lists that you will handle in your own way
109
+ # you may want to use two classes:
110
+ #
111
+ # * IPAccess::Set to maintain access sets (containing input and output access lists),
112
+ # * IPAccess::List to maintain single access list.
113
+ #
114
+ # === Using socket classes
115
+ #
116
+ # If you want standard sockets to have access control enabled
117
+ # you may want to use:
118
+ #
119
+ # * IPAccess::Socket (or issue <tt>IPAccess.arm Socket</tt>)
120
+ # * IPAccess::TCPSocket (or issue <tt>IPAccess.arm TCPSocket</tt>)
121
+ # * IPAccess::UDPSocket (or issue <tt>IPAccess.arm UDPSocket</tt>)
122
+ # * IPAccess::SOCKSocket (or issue <tt>IPAccess.arm SOCKSocket</tt>)
123
+ # * IPAccess::TCPServer (or issue <tt>IPAccess.arm TCPServer</tt>)
124
+ #
125
+ # Before using any of them you must issue:
126
+ #
127
+ # * <tt>require 'ipaccess/socket'</tt>
128
+ #
129
+ # Using the IPAccess.arm causes standard socket class to be altered,
130
+ # while <tt>IPAccess::</tt> classes are just new variants of socket
131
+ # handling classes.
132
+ #
133
+ # ==== Using other supported network classes
134
+ #
135
+ # If you want some working objects to have access control enabled
136
+ # you may want to use:
137
+ #
138
+ # * IPAccess::Net::Telnet (or issue <tt>IPAccess.arm Net::Telnet</tt>)
139
+ # * IPAccess::Net::HTTP (or issue <tt>IPAccess.arm Net::HTTP</tt>)
140
+ # * IPAccess::Net::FTP (or issue <tt>IPAccess.arm Net::FTP</tt>)
141
+ # * IPAccess::Net::POP3 (or issue <tt>IPAccess.arm Net::POP3</tt>)
142
+ # * IPAccess::Net::IMAP (or issue <tt>IPAccess.arm Net::IMAP</tt>)
143
+ # * IPAccess::Net::SMTP (or issue <tt>IPAccess.arm Net::SMTP</tt>)
144
+ #
145
+ # ==== Using single network objects
146
+ #
147
+ # If you want to enable access control for single network
148
+ # object from the list shown above you may issue:
149
+ #
150
+ # require 'ipaccess/net/http'
151
+ # obj = Net::HTTP.new(host, port)
152
+ # IPAccess.arm obj
153
+ #
154
+ # or
155
+ #
156
+ # require 'ipaccess/socket'
157
+ # socket = IPAccess::TCPServer.new(31337)
158
+ # IPAccess.arm socket
159
+ #
160
+ # ..and so on.
161
+ #
162
+ # === Structures
163
+ #
164
+ # IP addresses used by the classes are internaly and interfacialy
165
+ # represented by NetAddr::CIDR[http://netaddr.rubyforge.org/classes/NetAddr/CIDR.html]
166
+ # objects (NetAddr::CIDRv4[http://netaddr.rubyforge.org/classes/NetAddr/CIDRv4.html] and
167
+ # NetAddr::CIDRv6[http://netaddr.rubyforge.org/classes/NetAddr/CIDRv6.html]). Due to
168
+ # performance reasons any access list internally is represented as a tree
169
+ # (slightly modified NetAddr::Tree[http://netaddr.rubyforge.org/classes/NetAddr/Tree.html])
170
+ # with special tags assigning rules to virtual lists.
171
+ #
172
+ # === Relations
173
+ #
174
+ # Here is a diagram which shows relations
175
+ # between the IPAccess::TCPSocket class
176
+ # and other classes from this module:
177
+ #
178
+ # link:images/ipaccess_relations.png
179
+
180
+ module IPAccess
181
+
182
+ # This method converts names to NetAddr::CIDR objects. It returns an array of CIDR objects.
183
+ #
184
+ # Allowed input are strings (DNS names or IP addresses optionally with masks),
185
+ # numbers (IP addresses representation), IPSocket objects, URI objects, IPAddr objects,
186
+ # Net::HTTP objects, IPAddrList objects, NetAddr::CIDR objects, NetAddr::Tree objects,
187
+ # IPAccess::List objects, symbols, objects that contain file descriptors bound to sockets
188
+ # (including OpenSSL sockets) and arrays of these.
189
+ #
190
+ # In case of resolving the IPv6 link-local addresses
191
+ # zone index is removed. In case of DNS names there may
192
+ # occur Resolv::ResolvError exception. If there is an
193
+ # object that cannot be converted the ArgumentError
194
+ # exception is raised.
195
+ #
196
+ # When an argument called +:include_origins+ is present then the method will attach
197
+ # original converted objects to results as the +:Origin+ tag of CIDR objects
198
+ # (<tt>tag[:Origin]</tt>). This rule applies only to single objects or objects
199
+ # inside of arrays or sets. Objects that are kind of NetAddr::CIDR, IPAccess::Set,
200
+ # NetAddr::Tree and arrays will never be set as originators.
201
+ #
202
+ # ==== Examples
203
+ #
204
+ # to_cidrs("127.0.0.1") # uses the IP address
205
+ # to_cidrs(2130706433) # uses numeric representation of 127.0.0.1
206
+ # to_cidrs(:private, "localhost") # uses special symbol and DNS hostname
207
+ # to_cidrs(:private, :localhost) # uses special symbols
208
+ # to_cidrs [:private, :auto] # other way to write the above
209
+ # to_cidrs "10.0.0.0/8" # uses masked IP address
210
+ # to_cidrs "10.0.0.0/255.0.0.0" # uses masked IP address
211
+ # to_cidrs IPSocket.new("www.pl", 80) # uses the socket
212
+ # to_cidrs IPAddr("10.0.0.1") # uses IPAddr object
213
+ # to_cidrs NetAddr::CIDR.create("10.0.0.1") # uses NetAddr object
214
+ # to_cidrs URI('http://www.pl/') # uses URI
215
+ # to_cidrs 'http://www.pl/' # uses the extracted host string
216
+ # to_cidrs 'somehost.xx' # uses the host string (fetches ALL addresses from DNS)
217
+ # to_cidrs 'somehost.xx/16' # uses the host string and a netmask
218
+ #
219
+ # ==== Special symbols
220
+ #
221
+ # When symbol is passed to this method it tries to find out if it has special meaning.
222
+ # That allows you to create access rules in an easy way. For most of them you may
223
+ # also specify IP protocol version using +ipv4_+ or +ipv6_+ prefix.
224
+ #
225
+ # Known symbols are:
226
+ #
227
+ # <b>+:all+</b> (+:any+, +:anyone+, +:world+, +:internet+, +:net+, +:everything+, +:everyone+, +:everybody+, +:anybody+)
228
+ #
229
+ # variants: +:ipv4_+ and +:ipv6_+
230
+ #
231
+ # Creates masked IP address that matches all networks:
232
+ # – 0.0.0.0/0
233
+ # – ::/0
234
+ #
235
+ # <b>+:broadcast+</b> (+:brd+)
236
+ #
237
+ # variants: +:ipv4_+ and +:ipv6_+
238
+ #
239
+ # Creates masked IP address that matches generic broadcast address:
240
+ # – 255.255.255.255/32
241
+ # – ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128
242
+ #
243
+ # <b>+:local+</b> (+:localhost+, +:localdomain+, +:loopback+, +:lo+)
244
+ #
245
+ # variants: +:ipv4_+ and +:ipv6_+
246
+ #
247
+ # Creates masked IP addresses that match localhost:
248
+ # – 127.0.0.1/8
249
+ # – ::1/128
250
+ #
251
+ # <b>+:auto+</b> (+:automatic+, +:linklocal+)
252
+ #
253
+ # variants: +:ipv4_+ and +:ipv6_+
254
+ #
255
+ # Creates masked IP addresses that match automatically assigned address ranges:
256
+ # – 169.254.0.0/16
257
+ # – fe80::/10
258
+ #
259
+ # <b>+:private+</b> (+:intra+, +:intranet+, +:internal+)
260
+ #
261
+ # variants: +:ipv4_+ and +:ipv6_+
262
+ #
263
+ # Creates masked IP addresses that match private ranges:
264
+ # – 10.0.0.0/8
265
+ # – 172.16.0.0/12
266
+ # – 192.168.0.0/16
267
+ # – 2001:10::/28
268
+ # – 2001:db8::/32
269
+ # – fc00::/7
270
+ # – fdde:9e1a:dc85:7374::/64
271
+ #
272
+ # <b>+:multicast+</b> (+:multi+, +:multiemission+)
273
+ #
274
+ # variants: +:ipv4_+ and +:ipv6_+
275
+ #
276
+ # Creates masked IP addresses that match multicast addresses ranges:
277
+ # – 224.0.0.0/4
278
+ # – ff00::/8
279
+ # – ff02::1:ff00:0/104
280
+ #
281
+ # <b>+:reserved+</b> (+:example+)
282
+ #
283
+ # variants: +:ipv4_+
284
+ #
285
+ # Creates masked IP addresses that match reserved addresses ranges:
286
+ # – 192.0.2.0/24
287
+ # – 128.0.0.0/16
288
+ # – 191.255.0.0/16
289
+ # – 192.0.0.0/24
290
+ # – 198.18.0.0/15
291
+ # – 223.255.255.0/24
292
+ # – 240.0.0.0/4
293
+ #
294
+ # <b>+:strange+</b> (+:unusual+, +:nonpublic+, +:unpublic+)
295
+ #
296
+ # Creates masked IP addressess that match the following sets (both IPv4 and IPv6):
297
+ # – :local
298
+ # – :auto
299
+ # – :private
300
+ # – :reserved
301
+ # – :multicast
302
+
303
+ def self.to_cidrs(*addresses)
304
+ obj = addresses.flatten
305
+ include_origins = !!obj.reject!{ |x| x.is_a?(Symbol) && x == :include_origins }
306
+ if obj.size == 1
307
+ obj = obj.first
308
+ else
309
+ ary = []
310
+ obj.each do |o|
311
+ ary += ( include_origins ? to_cidrs(o, :include_origins) : to_cidrs(o) )
312
+ end
313
+ ary.flatten!
314
+ return ary
315
+ end
316
+
317
+ ori_obj = obj
318
+
319
+ # NetAddr::CIDR - immediate generation
320
+ if obj.is_a?(NetAddr::CIDR)
321
+ r = obj.dup
322
+ r.tag[:Originator] = ori_obj if include_origins
323
+ return [r]
324
+ end
325
+
326
+ # IPAccess::List - immediate generation
327
+ return obj.to_a if obj.is_a?(IPAccess::List)
328
+
329
+ # NetAddr::Tree - immediate generation
330
+ return obj.dump.map { |addr| addr[:CIDR] } if obj.is_a?(NetAddr::Tree)
331
+
332
+ # number or nil - immediate generation or exception
333
+ if (obj.is_a?(Numeric) || obj.nil?)
334
+ r = NetAddr::CIDR.create(obj)
335
+ r.tag[:Originator] = ori_obj if include_origins
336
+ return [r]
337
+ end
338
+
339
+ # object containing socket member (e.g. Net::HTTP) - fetch socket
340
+ if obj.respond_to?(:socket)
341
+ obj = obj.socket
342
+ elsif obj.respond_to?(:sock)
343
+ obj = obj.sock
344
+ elsif obj.respond_to?(:client_socket)
345
+ obj = obj.client_socket
346
+ elsif obj.instance_variable_defined?(:@socket)
347
+ obj = obj.instance_variable_get(:@socket)
348
+ elsif obj.instance_variable_defined?(:@client_socket)
349
+ obj = obj.instance_variable_get(:@client_socket)
350
+ elsif obj.instance_variable_defined?(:@sock)
351
+ obj = obj.instance_variable_get(:@sock)
352
+ end
353
+ obj = obj.io if (obj.respond_to?(:io) && obj.io.respond_to?(:getpeername))
354
+
355
+ # some file descriptor but not socket - fetch socket
356
+ obj = ::Socket.for_fd(obj.fileno) if (!obj.respond_to?(:getpeername) && obj.respond_to?(:fileno))
357
+
358
+ # Socket - immediate generation
359
+ if obj.respond_to?(:getpeername)
360
+ peeraddr = ::Socket.unpack_sockaddr_in(obj.getpeername).last.split('%').first
361
+ r = NetAddr::CIDR.create(peeraddr)
362
+ r.tag[:Originator] = ori_obj if include_origins
363
+ return [r]
364
+ end
365
+
366
+ # symbol - immediate generation
367
+ r_args = nil
368
+ if obj.is_a?(Symbol)
369
+ case obj
370
+ when :ipv4_all, :ipv4_any, :ipv4_anyone, :ipv4_world, :ipv4_internet, :ipv4_net, :ipv4_everything, :ipv4_everyone, :ipv4_everybody, :ipv4_anybody
371
+ obj = [ "0.0.0.0/0" ]
372
+ when :ipv6_all, :ipv6_any, :ipv6_anyone, :ipv6_world, :ipv6_internet, :ipv6_net, :ipv6_everything, :ipv6_everyone, :ipv6_everybody, :ipv6_anybody
373
+ obj = [ "0.0.0.0/0", "::/0" ]
374
+ when :ipv4_broadcast, :ipv4_brd
375
+ obj = [ "255.255.255.255/32" ]
376
+ when :ipv6_broadcast, :ipv6_brd
377
+ obj = [ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" ]
378
+ when :ipv4_local, :ipv4_localhost, :ipv4_loopback, :ipv4_lo
379
+ obj = [ "127.0.0.1/8" ]
380
+ when :ipv6_local, :ipv6_localhost, :ipv6_loopback, :ipv6_lo
381
+ obj = [ "::1/128" ]
382
+ when :ipv4_auto, :ipv4_automatic, :ipv4_linklocal
383
+ obj = [ "169.254.0.0/16" ]
384
+ when :ipv6_auto, :ipv6_automatic, :ipv6_linklocal
385
+ obj = [ "fe80::/10" ]
386
+ when :ipv4_private, :ipv4_intra, :ipv4_intranet, :ipv4_internal
387
+ obj = [ "10.0.0.0/8",
388
+ "172.16.0.0/12",
389
+ "192.168.0.0/16" ]
390
+ when :ipv6_private, :ipv6_intra, :ipv6_intranet, :ipv6_internal, :ipv6_ula, :ipv6_unique
391
+ obj = [ "2001:10::/28",
392
+ "2001:db8::/32",
393
+ "fc00::/7",
394
+ "fdde:9e1a:dc85:7374::/64" ]
395
+ when :ipv4_multicast, :ipv4_multi, :ipv4_multiemission
396
+ obj = [ "224.0.0.0/4" ]
397
+ when :ipv6_multicast, :ipv6_multi, :ipv6_multiemission
398
+ obj = [ "ff00::/8",
399
+ "ff02::1:ff00:0/104" ]
400
+ when :ipv4_example, :ipv4_reserved
401
+ obj = [ "192.0.2.0/24",
402
+ "128.0.0.0/16",
403
+ "191.255.0.0/16",
404
+ "192.0.0.0/24",
405
+ "198.18.0.0/15",
406
+ "223.255.255.0/24",
407
+ "240.0.0.0/4" ]
408
+ when :all, :any, :anyone, :world, :internet, :net, :everything, :everyone, :everybody, :anybody
409
+ r_args = [ :ipv4_all,
410
+ :ipv6_all ]
411
+ when :broadcast, :brd
412
+ r_args = [ :ipv4_broadcast,
413
+ :ipv6_broadcast ]
414
+ when :local, :localhost, :localdomain, :loopback, :lo
415
+ r_args = [ :ipv4_local,
416
+ :ipv6_local ]
417
+ when :auto, :automatic, :linklocal
418
+ r_args = [ :ipv4_auto,
419
+ :ipv6_auto ]
420
+ when :private, :intra, :intranet, :internal
421
+ r_args = [ :ipv4_private,
422
+ :ipv6_private ]
423
+ when :multicast, :multi, :multiemission
424
+ r_args = [ :ipv4_multicast,
425
+ :ipv6_multicast ]
426
+ when :reserved, :example
427
+ r_args = [ :ipv4_example ]
428
+ when :strange, :unusual, :nonpublic, :unpublic
429
+ r_args = [ :local,
430
+ :auto,
431
+ :private,
432
+ :reserved,
433
+ :multicast ]
434
+ else
435
+ raise ArgumentError, "Provided symbol is unknown: #{obj.to_s}"
436
+ end
437
+
438
+ unless r_args.nil?
439
+ r_args.push :include_origins if include_origins
440
+ return to_cidrs(*r_args)
441
+ end
442
+
443
+ # strange types here
444
+ if obj.is_a?(Array)
445
+ return obj.map do |addr|
446
+ r = NetAddr::CIDR.create(addr)
447
+ r.tag[:Originator] = addr if include_origins
448
+ r
449
+ end
450
+ end
451
+ end
452
+
453
+ # URI or something that responds to host method - fetch string
454
+ obj = obj.host if obj.respond_to?(:host)
455
+
456
+ # objects of external classes
457
+ case obj.class.name.to_sym
458
+ when :IPAddr # IPAddr - fetch IP/mask string
459
+ obj = obj.native.inspect.split[1].chomp('>')[5..-1]
460
+ when :IPAddrList # IPAddrList - pass array to parse
461
+ return include_origins ? to_cidrs(obj.to_a, :include_origins) : to_cidrs(obj.to_a)
462
+ end
463
+
464
+ # string or similar - immediate generation
465
+ if obj.respond_to?(:to_s)
466
+ hostmask = ""
467
+ obj = obj.to_s
468
+ # URI
469
+ if obj =~ /^[^:]+:\/\/(.*)/
470
+ obj = $1.split('/').first
471
+ # IP in URI
472
+ if obj =~ /^\[([^\]]+)\]/
473
+ obj = $1
474
+ else
475
+ obj = obj.split(':').first
476
+ end
477
+ # host(s) and a mask
478
+ elsif obj =~ /^([^\/]+)(\/((\d{1,2}$)|(\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b$)))/
479
+ obj = $1
480
+ hostmask = $2
481
+ end
482
+ begin
483
+ ipa = obj.split('%').first.to_s
484
+ r = NetAddr::CIDR.create(ipa + hostmask)
485
+ rescue NetAddr::ValidationError
486
+ begin
487
+ addresses = Resolv::getaddresses(obj)
488
+ rescue NoMethodError # unhandled error
489
+ raise Resolv::ResolvError, "not connected or network error"
490
+ end
491
+ addresses.map! do |addr|
492
+ begin
493
+ r = NetAddr::CIDR.create(addr.split('%').first + hostmask)
494
+ r.tag[:Originator] = ori_obj
495
+ r
496
+ rescue ArgumentError
497
+ nil
498
+ end
499
+ end
500
+ addresses.flatten!
501
+ addresses.compact!
502
+ return addresses
503
+ end
504
+ r.tag[:Originator] = ori_obj
505
+ return [r]
506
+ end
507
+
508
+ # should never happend
509
+ r = obj.is_a?(NetAddr::CIDR) ? obj.dup : NetAddr::CIDR.create(obj.to_s)
510
+ r.tag[:Originator] = ori_obj
511
+ return [r]
512
+ end
513
+
514
+ # This method calls IPAccess.to_cidrs
515
+ # and returns first obtained entry containing
516
+ # single IP address with mask (NetAddr::CIDR).
517
+
518
+ def self.to_cidr(*addresses)
519
+ r = self.to_cidrs(*addresses)
520
+ return r.respond_to?(:first) ? first : r
521
+ end
522
+
523
+ end