ipaccess 0.0.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.
- data/Rakefile +64 -0
- data/docs/COPYING +61 -0
- data/docs/DOWNLOAD +17 -0
- data/docs/LEGAL +11 -0
- data/docs/LGPL-LICENSE +169 -0
- data/docs/README +95 -0
- data/docs/TODO +18 -0
- data/docs/WELCOME +8 -0
- data/examples/tcp_socket.rb +9 -0
- data/lib/ipaccess.rb +35 -0
- data/lib/ipaccess/arm_sockets.rb +33 -0
- data/lib/ipaccess/ghost_doc.rb +206 -0
- data/lib/ipaccess/ghost_doc_acl.rb +31 -0
- data/lib/ipaccess/ip_access.rb +455 -0
- data/lib/ipaccess/ip_access_errors.rb +131 -0
- data/lib/ipaccess/ip_access_list.rb +1209 -0
- data/lib/ipaccess/ip_access_patches.rb +435 -0
- data/lib/ipaccess/netaddr_patch.rb +127 -0
- data/lib/ipaccess/sockets.rb +53 -0
- data/spec/core_spec.rb +5 -0
- data/spec/ip_access_list_spec.rb +302 -0
- data/spec/rcov.opts +7 -0
- data/spec/spec.opts +2 -0
- metadata +84 -0
@@ -0,0 +1,435 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Author:: Paweł Wilk (mailto:pw@gnu.org)
|
4
|
+
# Copyright:: Copyright (c) 2009 Paweł Wilk
|
5
|
+
# License:: This program is licensed under the terms of {GNU Lesser General Public License}[link:docs/LGPL-LICENSE.html] or {Ruby License}[link:docs/COPYING.html].
|
6
|
+
#
|
7
|
+
# Modules contained in this file are meant for
|
8
|
+
# patching Ruby socket classes in order to add
|
9
|
+
# IP access control to them.
|
10
|
+
#
|
11
|
+
#--
|
12
|
+
#
|
13
|
+
# Copyright (C) 2009 by Paweł Wilk. All Rights Reserved.
|
14
|
+
#
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
16
|
+
# it under the terms of either: 1) the GNU Lesser General Public License
|
17
|
+
# as published by the Free Software Foundation; either version 3 of the
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
19
|
+
#
|
20
|
+
# See the file COPYING for complete licensing information.
|
21
|
+
#
|
22
|
+
#++
|
23
|
+
#
|
24
|
+
|
25
|
+
require 'socket'
|
26
|
+
require 'singleton'
|
27
|
+
require 'ipaccess/ip_access_errors'
|
28
|
+
|
29
|
+
class IPAccess
|
30
|
+
|
31
|
+
# This is global access set, used by
|
32
|
+
# default by all socket handling
|
33
|
+
# classes with enabled IP access control.
|
34
|
+
|
35
|
+
Global = IPAccess.new 'global'
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# :stopdoc:
|
40
|
+
|
41
|
+
# This modules contain patches for Ruby socket
|
42
|
+
# classes in order to enable IP access control
|
43
|
+
# for them.
|
44
|
+
#
|
45
|
+
# This module patches socket handling classes
|
46
|
+
# to use IP access control. Each patched socket
|
47
|
+
# class has acl member, which is an IPAccess object.
|
48
|
+
|
49
|
+
module IPAccess::Patches
|
50
|
+
|
51
|
+
# This class is a proxy that raises an exception when
|
52
|
+
# any method other than defined in Object class is called.
|
53
|
+
# It behaves like NilClass.
|
54
|
+
|
55
|
+
class GlobalSet
|
56
|
+
|
57
|
+
include Singleton
|
58
|
+
|
59
|
+
def nil?; true end
|
60
|
+
|
61
|
+
def method_missing(name, *args)
|
62
|
+
return nil.method(name).call(*args) if nil.respond_to?(name)
|
63
|
+
raise ArgumentError, "cannot access global set from object's scope, use IPAccess::Global"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# The IPSocketAccess module contains methods
|
70
|
+
# that are present in all classes handling
|
71
|
+
# sockets with IP access control enabled.
|
72
|
+
|
73
|
+
module IPSocketAccess
|
74
|
+
|
75
|
+
# This method enables usage of internal IP access list for object.
|
76
|
+
# If argument is IPAccess object then it is used.
|
77
|
+
#
|
78
|
+
# ==== Example
|
79
|
+
#
|
80
|
+
# socket.acl = :global # use global access set
|
81
|
+
# socket.acl = :private # create and use individual access set
|
82
|
+
# socket.acl = IPAccess.new # use external (shared) access set
|
83
|
+
|
84
|
+
def acl=(obj)
|
85
|
+
if obj.is_a?(Symbol)
|
86
|
+
case obj
|
87
|
+
when :global
|
88
|
+
@acl = GlobalSet.instance
|
89
|
+
when :private
|
90
|
+
@acl = IPAccess.new
|
91
|
+
else
|
92
|
+
raise ArgumentError, "bad access list selector, use: :global or :private"
|
93
|
+
end
|
94
|
+
elsif obj.is_a?(IPAccess)
|
95
|
+
@acl = obj
|
96
|
+
else
|
97
|
+
raise ArgumentError, "bad access list"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
attr_reader :acl
|
102
|
+
alias_method :access=, :acl=
|
103
|
+
alias_method :access, :acl
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
###################################################################
|
108
|
+
# Socket class with IP access control.
|
109
|
+
# It uses input and output access lists.
|
110
|
+
|
111
|
+
module Socket
|
112
|
+
|
113
|
+
include IPSocketAccess
|
114
|
+
|
115
|
+
def self.included(base)
|
116
|
+
|
117
|
+
marker = (base.name =~ /IPAccess/) ? base.superclass : base
|
118
|
+
return if marker.instance_variable_defined?(:@uses_ipaccess)
|
119
|
+
base.instance_variable_set(:@uses_ipaccess, true)
|
120
|
+
|
121
|
+
base.class_eval do
|
122
|
+
|
123
|
+
orig_initialize = self.instance_method :initialize
|
124
|
+
orig_accept = self.instance_method :accept
|
125
|
+
orig_accept_nonblock = self.instance_method :accept_nonblock
|
126
|
+
orig_connect = self.instance_method :connect
|
127
|
+
orig_recvfrom = self.instance_method :recvfrom
|
128
|
+
orig_recvfrom_nonblock = self.instance_method :recvfrom_nonblock
|
129
|
+
orig_sysaccept = self.instance_method :sysaccept
|
130
|
+
|
131
|
+
define_method :initialize do |*args|
|
132
|
+
@acl = GlobalSet.instance
|
133
|
+
orig_initialize(*args)
|
134
|
+
return self
|
135
|
+
end
|
136
|
+
|
137
|
+
# accept on steroids.
|
138
|
+
define_method :accept do |*args|
|
139
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
140
|
+
ret = orig_accept.bind(self).call(*args)
|
141
|
+
acl.check_in_socket(ret.first)
|
142
|
+
return ret
|
143
|
+
end
|
144
|
+
|
145
|
+
# accept_nonblock on steroids.
|
146
|
+
define_method :accept_nonblock do |*args|
|
147
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
148
|
+
ret = orig_accept_nonblock.bind(self).call(*args)
|
149
|
+
acl.check_in_socket(ret.first)
|
150
|
+
return ret
|
151
|
+
end
|
152
|
+
|
153
|
+
# sysaccept on steroids.
|
154
|
+
define_method :sysaccept do |*args|
|
155
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
156
|
+
ret = orig_accept.bind(self).call(*args)
|
157
|
+
acl.check_in_sockaddr(ret.last)
|
158
|
+
return ret
|
159
|
+
end
|
160
|
+
|
161
|
+
# connect on steroids.
|
162
|
+
define_method :connect do |*args|
|
163
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
164
|
+
acl.check_out_sockaddr(args.first)
|
165
|
+
return orig_connect.bind(self).call(*args)
|
166
|
+
end
|
167
|
+
|
168
|
+
# recvfrom on steroids.
|
169
|
+
define_method :recvfrom do |*args|
|
170
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
171
|
+
ret = orig_recvfrom.bind(self).call(*args)
|
172
|
+
peer_ip = ret[1][3]
|
173
|
+
family = ret[1][0]
|
174
|
+
if (family == "AF_INET" || family == "AF_INET6")
|
175
|
+
acl.check_in_ipstring(peer_ip)
|
176
|
+
end
|
177
|
+
return ret
|
178
|
+
end
|
179
|
+
|
180
|
+
# recvfrom_nonblock on steroids.
|
181
|
+
define_method :recvfrom_nonblock do |*args|
|
182
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
183
|
+
ret = orig_recvfrom_nonblock.bind(self).call(*args)
|
184
|
+
peer_ip = ret[1][3]
|
185
|
+
family = ret[1][0]
|
186
|
+
if (family == "AF_INET" || family == "AF_INET6")
|
187
|
+
acl.check_in_ipstring(peer_ip)
|
188
|
+
end
|
189
|
+
return ret
|
190
|
+
end
|
191
|
+
|
192
|
+
end # base.class_eval
|
193
|
+
|
194
|
+
end # self.included
|
195
|
+
|
196
|
+
end # module Socket
|
197
|
+
|
198
|
+
###################################################################
|
199
|
+
# UDPSocket class with IP access control.
|
200
|
+
# It uses input and output access lists.
|
201
|
+
|
202
|
+
module UDPSocket
|
203
|
+
|
204
|
+
include IPSocketAccess
|
205
|
+
|
206
|
+
def self.included(base)
|
207
|
+
|
208
|
+
marker = (base.name =~ /IPAccess/) ? base.superclass : base
|
209
|
+
return if marker.instance_variable_defined?(:@uses_ipaccess)
|
210
|
+
base.instance_variable_set(:@uses_ipaccess, true)
|
211
|
+
|
212
|
+
base.class_eval do
|
213
|
+
|
214
|
+
orig_initialize = self.instance_method :initialize
|
215
|
+
orig_connect = self.instance_method :connect
|
216
|
+
orig_send = self.instance_method :send
|
217
|
+
orig_recvfrom = self.instance_method :recvfrom
|
218
|
+
orig_recvfrom_nonblock = self.instance_method :recvfrom_nonblock
|
219
|
+
|
220
|
+
define_method :initialize do |*args|
|
221
|
+
@acl = GlobalSet.instance
|
222
|
+
orig_initialize(*args)
|
223
|
+
return self
|
224
|
+
end
|
225
|
+
|
226
|
+
# connect on steroids.
|
227
|
+
define_method :connect do |*args|
|
228
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
229
|
+
peer_ip = self.class.getaddress(args.shift)
|
230
|
+
acl.check_out_sockaddr(peer_ip)
|
231
|
+
return orig_connect.bind(self).call(peer_ip, *args)
|
232
|
+
end
|
233
|
+
|
234
|
+
# send on steroids.
|
235
|
+
define_method :send do |*args|
|
236
|
+
hostname = args[2]
|
237
|
+
return orig_send(*args) if hostname.nil?
|
238
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
239
|
+
peer_ip = self.class.getaddress(hostname)
|
240
|
+
acl.check_out_sockaddr(peer_ip)
|
241
|
+
args[2] = peer_ip
|
242
|
+
return orig_send.bind(self).call(*args)
|
243
|
+
end
|
244
|
+
|
245
|
+
# recvfrom on steroids.
|
246
|
+
define_method :recvfrom do |*args|
|
247
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
248
|
+
ret = orig_recvfrom.bind(self).call(*args)
|
249
|
+
peer_ip = ret[1][3]
|
250
|
+
family = ret[1][0]
|
251
|
+
if (family == "AF_INET" || family == "AF_INET6")
|
252
|
+
acl.check_in_ipstring(peer_ip)
|
253
|
+
end
|
254
|
+
return ret
|
255
|
+
end
|
256
|
+
|
257
|
+
# recvfrom_nonblock on steroids.
|
258
|
+
define_method :recvfrom_nonblock do |*args|
|
259
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
260
|
+
ret = orig_recvfrom_nonblock.bind(self).call(*args)
|
261
|
+
peer_ip = ret[1][3]
|
262
|
+
family = ret[1][0]
|
263
|
+
if (family == "AF_INET" || family == "AF_INET6")
|
264
|
+
acl.check_in_ipstring(peer_ip)
|
265
|
+
end
|
266
|
+
return ret
|
267
|
+
end
|
268
|
+
|
269
|
+
end # base.class_eval
|
270
|
+
|
271
|
+
end # self.included
|
272
|
+
|
273
|
+
end # module UDPSocket
|
274
|
+
|
275
|
+
###################################################################
|
276
|
+
# SOCKSSocket class with IP access control.
|
277
|
+
# It uses output access lists.
|
278
|
+
|
279
|
+
module SOCKSocket
|
280
|
+
|
281
|
+
include IPSocketAccess
|
282
|
+
|
283
|
+
def self.included(base)
|
284
|
+
|
285
|
+
marker = (base.name =~ /IPAccess/) ? base.superclass : base
|
286
|
+
return if marker.instance_variable_defined?(:@uses_ipaccess)
|
287
|
+
base.instance_variable_set(:@uses_ipaccess, true)
|
288
|
+
|
289
|
+
base.class_eval do
|
290
|
+
|
291
|
+
orig_initialize = self.instance_method :initialize
|
292
|
+
|
293
|
+
# initialize on steroids.
|
294
|
+
define_method :initialize do |*args|
|
295
|
+
self.acl = (args.size > 2) ? args.pop : :global
|
296
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
297
|
+
args[0] = self.class.getaddress(args[0])
|
298
|
+
acl.check_out_ipstring args[0]
|
299
|
+
orig_initialize.bind(self).call(*args)
|
300
|
+
return self
|
301
|
+
end
|
302
|
+
|
303
|
+
end # base.class_eval
|
304
|
+
|
305
|
+
end # self.included
|
306
|
+
|
307
|
+
end # module SOCKSSocket
|
308
|
+
|
309
|
+
###################################################################
|
310
|
+
# TCPSocket class with IP access control.
|
311
|
+
# It uses output access lists.
|
312
|
+
|
313
|
+
module TCPSocket
|
314
|
+
|
315
|
+
include IPSocketAccess
|
316
|
+
|
317
|
+
def self.included(base)
|
318
|
+
|
319
|
+
marker = (base.name =~ /IPAccess/) ? base.superclass : base
|
320
|
+
return if marker.instance_variable_defined?(:@uses_ipaccess)
|
321
|
+
base.instance_variable_set(:@uses_ipaccess, true)
|
322
|
+
|
323
|
+
base.class_eval do
|
324
|
+
|
325
|
+
orig_initialize = self.instance_method :initialize
|
326
|
+
|
327
|
+
# initialize on steroids.
|
328
|
+
define_method :initialize do |*args|
|
329
|
+
self.acl = (args.size > 2) ? args.pop : :global
|
330
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
331
|
+
args[0] = self.class.getaddress(args[0])
|
332
|
+
acl.check_out_ipstring args[0]
|
333
|
+
orig_initialize.bind(self).call(*args)
|
334
|
+
return self
|
335
|
+
end
|
336
|
+
|
337
|
+
end # base.class_eval
|
338
|
+
|
339
|
+
end # self.included
|
340
|
+
|
341
|
+
end # module TCPSocket
|
342
|
+
|
343
|
+
###################################################################
|
344
|
+
# TCPServer class with IP access control.
|
345
|
+
# It uses input access lists.
|
346
|
+
|
347
|
+
module TCPServer
|
348
|
+
|
349
|
+
include IPSocketAccess
|
350
|
+
|
351
|
+
def self.included(base)
|
352
|
+
|
353
|
+
marker = (base.name =~ /IPAccess/) ? base.superclass : base
|
354
|
+
return if marker.instance_variable_defined?(:@uses_ipaccess)
|
355
|
+
base.instance_variable_set(:@uses_ipaccess, true)
|
356
|
+
|
357
|
+
base.class_eval do
|
358
|
+
|
359
|
+
orig_initialize = self.instance_method :initialize
|
360
|
+
orig_accept = self.instance_method :accept
|
361
|
+
orig_accept_nonblock = self.instance_method :accept_nonblock
|
362
|
+
orig_sysaccept = self.instance_method :sysaccept
|
363
|
+
|
364
|
+
# initialize on steroids.
|
365
|
+
define_method :initialize do |*args|
|
366
|
+
@acl = GlobalSet.instance
|
367
|
+
return orig_initialize.bind(self).call(*args)
|
368
|
+
end
|
369
|
+
|
370
|
+
# accept on steroids.
|
371
|
+
define_method :accept do |*args|
|
372
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
373
|
+
acl.check_in_socket orig_accept.bind(self).call(*args)
|
374
|
+
end
|
375
|
+
|
376
|
+
# accept_nonblock on steroids.
|
377
|
+
define_method :accept_nonblock do |*args|
|
378
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
379
|
+
acl.check_in_socket orig_accept_nonblock.bind(self).call(*args)
|
380
|
+
end
|
381
|
+
|
382
|
+
# sysaccept on steroids.
|
383
|
+
define_method :sysaccept do |*args|
|
384
|
+
acl = @acl.nil? ? IPAccess::Global : @acl
|
385
|
+
acl.check_in_fd orig_sysaccept.bind(self).call(*args)
|
386
|
+
end
|
387
|
+
|
388
|
+
end # base.class_eval
|
389
|
+
|
390
|
+
end # self.included
|
391
|
+
|
392
|
+
end # module TCPServer
|
393
|
+
|
394
|
+
end # module IPAccess::Patches
|
395
|
+
|
396
|
+
# :startdoc:
|
397
|
+
|
398
|
+
class IPAccess
|
399
|
+
|
400
|
+
# This special method patches Ruby's standard
|
401
|
+
# library socket handling classes and enables
|
402
|
+
# IP access control for them. Instances of
|
403
|
+
# such altered classes will be equipped with
|
404
|
+
# member called +acl+ which is a kind of
|
405
|
+
# IPAccess and allows you to manipulate
|
406
|
+
# access rules.
|
407
|
+
#
|
408
|
+
# Passed argument may be a class object,
|
409
|
+
# a string representation of a class object
|
410
|
+
# or a symbol representing a class object.
|
411
|
+
#
|
412
|
+
# Currently supported classes are:
|
413
|
+
# +Socket+, +UDPSocket+, +SOCKSSocket+,
|
414
|
+
# +TCPSocket+ and +TCPServer+.
|
415
|
+
#
|
416
|
+
# Example:
|
417
|
+
#
|
418
|
+
# IPAccess.arm TCPSocket # arm TCPSocket class
|
419
|
+
# IPAccess::Global.output.blacklist 'randomseed.pl' # add host to black list of the global set
|
420
|
+
# TCPSocket.new('randomseed.pl', 80) # try to connect
|
421
|
+
|
422
|
+
def self.arm(klass)
|
423
|
+
klass_name = klass.name if klass.is_a?(Class)
|
424
|
+
klass_name = klass_name.to_s unless klass.is_a?(String)
|
425
|
+
klass_name = klass_name.to_sym
|
426
|
+
case klass_name
|
427
|
+
when :Socket, :UDPSocket, :SOCKSSocket, :TCPSocket, :TCPServer
|
428
|
+
klass.__send__(:include, Patches.const_get(klass_name))
|
429
|
+
else
|
430
|
+
raise ArgumentError, "cannot enable IP access control for class #{klass_name}"
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
end
|
435
|
+
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# Author:: Paweł Wilk (mailto:pw@gnu.org)
|
4
|
+
# Copyright:: Copyright (c) 2009 Paweł Wilk
|
5
|
+
# License:: This program is licensed under the terms of {GNU Lesser General Public License}[link:docs/LGPL-LICENSE.html] or {Ruby License}[link:docs/COPYING.html].
|
6
|
+
#
|
7
|
+
# This file extends NetAddr by adding methods
|
8
|
+
# that bring some comfort into IPv6 handling.
|
9
|
+
#
|
10
|
+
#--
|
11
|
+
#
|
12
|
+
# Copyright (C) 2009 by Paweł Wilk. All Rights Reserved.
|
13
|
+
#
|
14
|
+
# This program is free software; you can redistribute it and/or modify
|
15
|
+
# it under the terms of either: 1) the GNU Lesser General Public License
|
16
|
+
# as published by the Free Software Foundation; either version 3 of the
|
17
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
18
|
+
#
|
19
|
+
# See the file COPYING for complete licensing information.
|
20
|
+
#
|
21
|
+
#++
|
22
|
+
|
23
|
+
require 'netaddr'
|
24
|
+
|
25
|
+
# This module contains few new methods extending
|
26
|
+
# original NetAddr module.
|
27
|
+
|
28
|
+
module NetAddr
|
29
|
+
|
30
|
+
# :stopdoc:
|
31
|
+
|
32
|
+
class CIDR
|
33
|
+
|
34
|
+
# Returns +true+ if the IP address is an IPv4-mapped IPv6 address.
|
35
|
+
|
36
|
+
def ipv4_mapped?
|
37
|
+
return @version == 6 && (@ip >> 32) == 0xffff
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns +true+ if the IP address is an IPv4-compatible IPv6 address.
|
41
|
+
|
42
|
+
def ipv4_compat?
|
43
|
+
return false if @version != 6
|
44
|
+
return false if (@ip >> 32) != 0
|
45
|
+
a = (@ip & 0xffffffff)
|
46
|
+
return (a != 0 && a != 1)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns +true+ if the IP address is an IPv4-compatible or
|
50
|
+
# IPv4-mapped IPv6 address.
|
51
|
+
|
52
|
+
def ipv4_compliant?
|
53
|
+
return false if @version != 6
|
54
|
+
a = (@ip >> 32)
|
55
|
+
return (a == 0xffff) if a.nonzero?
|
56
|
+
a = (@ip & 0xffffffff)
|
57
|
+
return (a != 0 && a != 1)
|
58
|
+
end
|
59
|
+
|
60
|
+
# This method duplicates CIDR and removes
|
61
|
+
# tags specified as symbols. It returns new
|
62
|
+
# Netaddr::CIDR object.
|
63
|
+
|
64
|
+
def safe_dup(*tags_to_remove)
|
65
|
+
tags = self.tag.dup
|
66
|
+
tags_to_remove.each { |t| tags.delete t }
|
67
|
+
return NetAddr.cidr_build(
|
68
|
+
@version,
|
69
|
+
@network,
|
70
|
+
@netmask,
|
71
|
+
tags,
|
72
|
+
@wildcard_mask)
|
73
|
+
end
|
74
|
+
|
75
|
+
end # class CIDR
|
76
|
+
|
77
|
+
class CIDRv4
|
78
|
+
|
79
|
+
# Returns a new NetAddr::CIDRv6 object built by converting
|
80
|
+
# the native IPv4 address to an IPv4-mapped IPv6 address.
|
81
|
+
# Mask is also converted.
|
82
|
+
|
83
|
+
def ipv4_mapped
|
84
|
+
return NetAddr::CIDR.create(@ip | 0xffff00000000,
|
85
|
+
:Mask => @netmask << 96,
|
86
|
+
:Version => 6)
|
87
|
+
end
|
88
|
+
|
89
|
+
alias_method :ipv6, :ipv4_mapped
|
90
|
+
alias_method :to_ipv6, :ipv4_mapped
|
91
|
+
|
92
|
+
# Returns a new NetAddr::CIDRv6 object built by converting
|
93
|
+
# the native IPv4 address to an IPv4-compatible IPv6 address.
|
94
|
+
# Mask is also converted.
|
95
|
+
|
96
|
+
def ipv4_compat
|
97
|
+
return NetAddr::CIDR.create(@ip,
|
98
|
+
:Mask => @netmask << 96,
|
99
|
+
:Version => 6)
|
100
|
+
end
|
101
|
+
|
102
|
+
end # class CIDRv4
|
103
|
+
|
104
|
+
class CIDRv6
|
105
|
+
|
106
|
+
def ipv4
|
107
|
+
if ipv4_mapped?
|
108
|
+
ip = @ip ^ 0xffff00000000
|
109
|
+
elsif ipv4_compat?
|
110
|
+
ip = @ip
|
111
|
+
else
|
112
|
+
raise VersionError, "Attempted to create version 4 CIDR " +
|
113
|
+
"with non-compliant CIDR item in version #{@version}."
|
114
|
+
end
|
115
|
+
return NetAddr::CIDR.create(ip,
|
116
|
+
:Mask => @netmask >> 96,
|
117
|
+
:Version => 4)
|
118
|
+
end
|
119
|
+
|
120
|
+
alias_method :to_ipv4, :ipv4
|
121
|
+
|
122
|
+
end # class CIDRv4
|
123
|
+
|
124
|
+
# :startdoc:
|
125
|
+
|
126
|
+
end # module NetAddr
|
127
|
+
|