ipaddress_2 0.11.0
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 +7 -0
- data/.byebug_history +25 -0
- data/.document +5 -0
- data/.gitignore +20 -0
- data/.rock.yml +5 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +31 -0
- data/CHANGELOG.rdoc +115 -0
- data/CONTRIBUTING.md +39 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +964 -0
- data/Rakefile +69 -0
- data/VERSION +1 -0
- data/ipaddress_2.gemspec +30 -0
- data/lib/ipaddress_2/ipv4.rb +1204 -0
- data/lib/ipaddress_2/ipv6.rb +1274 -0
- data/lib/ipaddress_2/mongoid.rb +75 -0
- data/lib/ipaddress_2/prefix.rb +285 -0
- data/lib/ipaddress_2/version.rb +3 -0
- data/lib/ipaddress_2.rb +293 -0
- data/test/ipaddress_2/ipv4_test.rb +701 -0
- data/test/ipaddress_2/ipv6_test.rb +707 -0
- data/test/ipaddress_2/mongoid_test.rb +70 -0
- data/test/ipaddress_2/prefix_test.rb +171 -0
- data/test/ipaddress_2_test.rb +109 -0
- data/test/test_helper.rb +37 -0
- metadata +195 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
module IPAddress
|
2
|
+
|
3
|
+
#
|
4
|
+
# Mongoid field serialization
|
5
|
+
#
|
6
|
+
# IPAddress objects are converted to String
|
7
|
+
#
|
8
|
+
# IPAddress.mongoize IPAddress.parse("172.16.10.1")
|
9
|
+
# #=> "172.16.10.1"
|
10
|
+
#
|
11
|
+
# Prefix will be removed from host adresses
|
12
|
+
#
|
13
|
+
# IPAddress.mongoize "172.16.10.1/32"
|
14
|
+
# #=> "172.16.10.1"
|
15
|
+
#
|
16
|
+
# Prefix will be kept for network addresses
|
17
|
+
#
|
18
|
+
# IPAddress.mongoize "172.16.10.1/24"
|
19
|
+
# #=> "172.16.10.1/24"
|
20
|
+
#
|
21
|
+
# IPv6 addresses will be stored uncompressed to ease DB search and sorting
|
22
|
+
#
|
23
|
+
# IPAddress.mongoize "2001:db8::8:800:200c:417a"
|
24
|
+
# #=> "2001:0db8:0000:0000:0008:0800:200c:417a"
|
25
|
+
# IPAddress.mongoize "2001:db8::8:800:200c:417a/64"
|
26
|
+
# #=> "2001:0db8:0000:0000:0008:0800:200c:417a/64"
|
27
|
+
#
|
28
|
+
# Invalid addresses will be serialized as nil
|
29
|
+
#
|
30
|
+
# IPAddress.mongoize "invalid"
|
31
|
+
# #=> nil
|
32
|
+
# IPAddress.mongoize ""
|
33
|
+
# #=> nil
|
34
|
+
# IPAddress.mongoize 1
|
35
|
+
# #=> nil
|
36
|
+
# IPAddress.mongoize nil
|
37
|
+
# #=> nil
|
38
|
+
#
|
39
|
+
def self.mongoize(ipaddress)
|
40
|
+
ipaddress = self.parse(ipaddress) unless ipaddress.is_a?(IPAddress)
|
41
|
+
if ipaddress.bits.length == ipaddress.prefix
|
42
|
+
ipaddress.address
|
43
|
+
elsif ipaddress.is_a?(IPAddress::IPv6)
|
44
|
+
ipaddress.to_string_uncompressed
|
45
|
+
else
|
46
|
+
ipaddress.to_string
|
47
|
+
end
|
48
|
+
rescue ArgumentError
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Mongoid field deserialization
|
54
|
+
#
|
55
|
+
def self.demongoize(string)
|
56
|
+
parse(string)
|
57
|
+
rescue ArgumentError
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Delegates to IPAddress.mongoize
|
63
|
+
#
|
64
|
+
def self.evolve(ipaddress)
|
65
|
+
mongoize(ipaddress)
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Sends self object to IPAddress#mongoize
|
70
|
+
#
|
71
|
+
def mongoize
|
72
|
+
IPAddress.mongoize(self)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
@@ -0,0 +1,285 @@
|
|
1
|
+
module IPAddress
|
2
|
+
|
3
|
+
#
|
4
|
+
# =NAME
|
5
|
+
#
|
6
|
+
# IPAddress::Prefix
|
7
|
+
#
|
8
|
+
# =SYNOPSIS
|
9
|
+
#
|
10
|
+
# Parent class for Prefix32 and Prefix128
|
11
|
+
#
|
12
|
+
# =DESCRIPTION
|
13
|
+
#
|
14
|
+
# IPAddress::Prefix is the parent class for IPAddress::Prefix32
|
15
|
+
# and IPAddress::Prefix128, defining some modules in common for
|
16
|
+
# both the subclasses.
|
17
|
+
#
|
18
|
+
# IPAddress::Prefix shouldn't be accesses directly, unless
|
19
|
+
# for particular needs.
|
20
|
+
#
|
21
|
+
class Prefix
|
22
|
+
|
23
|
+
include Comparable
|
24
|
+
|
25
|
+
attr_reader :prefix
|
26
|
+
|
27
|
+
#
|
28
|
+
# Creates a new general prefix
|
29
|
+
#
|
30
|
+
def initialize(num)
|
31
|
+
@prefix = num.to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Returns a string with the prefix
|
36
|
+
#
|
37
|
+
def to_s
|
38
|
+
"#@prefix"
|
39
|
+
end
|
40
|
+
alias_method :inspect, :to_s
|
41
|
+
|
42
|
+
#
|
43
|
+
# Returns the prefix
|
44
|
+
#
|
45
|
+
def to_i
|
46
|
+
@prefix
|
47
|
+
end
|
48
|
+
alias_method :to_int, :to_i
|
49
|
+
|
50
|
+
#
|
51
|
+
# Provides support for Ruby type coercion
|
52
|
+
#
|
53
|
+
def coerce(other)
|
54
|
+
case other
|
55
|
+
when Integer
|
56
|
+
[other, @prefix]
|
57
|
+
else
|
58
|
+
other.coerce(@prefix).reverse!
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Compare the prefix
|
64
|
+
#
|
65
|
+
def <=>(oth)
|
66
|
+
if oth.is_a? Integer
|
67
|
+
@prefix <=> oth
|
68
|
+
else
|
69
|
+
x, y = oth.coerce(@prefix)
|
70
|
+
x <=> y
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# Sums two prefixes or a prefix to a
|
76
|
+
# number, returns a Integer
|
77
|
+
#
|
78
|
+
def +(oth)
|
79
|
+
if oth.is_a? Integer
|
80
|
+
self.prefix + oth
|
81
|
+
else
|
82
|
+
x, y = oth.coerce(@prefix)
|
83
|
+
x + y
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
#
|
88
|
+
# Returns the difference between two
|
89
|
+
# prefixes, or a prefix and a number,
|
90
|
+
# as a Integer
|
91
|
+
#
|
92
|
+
def -(oth)
|
93
|
+
if oth.is_a? Integer
|
94
|
+
self.prefix - oth
|
95
|
+
else
|
96
|
+
x, y = oth.coerce(@prefix)
|
97
|
+
x - y
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end # class Prefix
|
102
|
+
|
103
|
+
|
104
|
+
class Prefix32 < Prefix
|
105
|
+
|
106
|
+
IN4MASK = 0xffffffff
|
107
|
+
|
108
|
+
#
|
109
|
+
# Creates a new prefix object for 32 bits IPv4 addresses
|
110
|
+
#
|
111
|
+
# prefix = IPAddress::Prefix32.new 24
|
112
|
+
# #=> 24
|
113
|
+
#
|
114
|
+
def initialize(num)
|
115
|
+
unless (0..32).include? num
|
116
|
+
raise ArgumentError, "Prefix must be in range 0..32, got: #{num}"
|
117
|
+
end
|
118
|
+
super(num)
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# Returns the length of the host portion
|
123
|
+
# of a netmask.
|
124
|
+
#
|
125
|
+
# prefix = Prefix32.new 24
|
126
|
+
#
|
127
|
+
# prefix.host_prefix
|
128
|
+
# #=> 8
|
129
|
+
#
|
130
|
+
def host_prefix
|
131
|
+
32 - @prefix
|
132
|
+
end
|
133
|
+
|
134
|
+
#
|
135
|
+
# Transforms the prefix into a string of bits
|
136
|
+
# representing the netmask
|
137
|
+
#
|
138
|
+
# prefix = IPAddress::Prefix32.new 24
|
139
|
+
#
|
140
|
+
# prefix.bits
|
141
|
+
# #=> "11111111111111111111111100000000"
|
142
|
+
#
|
143
|
+
def bits
|
144
|
+
"%.32b" % to_u32
|
145
|
+
end
|
146
|
+
|
147
|
+
#
|
148
|
+
# Gives the prefix in IPv4 dotted decimal format,
|
149
|
+
# i.e. the canonical netmask we're all used to
|
150
|
+
#
|
151
|
+
# prefix = IPAddress::Prefix32.new 24
|
152
|
+
#
|
153
|
+
# prefix.to_ip
|
154
|
+
# #=> "255.255.255.0"
|
155
|
+
#
|
156
|
+
def to_ip
|
157
|
+
[bits].pack("B*").unpack("CCCC").join(".")
|
158
|
+
end
|
159
|
+
|
160
|
+
#
|
161
|
+
# An array of octets of the IPv4 dotted decimal
|
162
|
+
# format
|
163
|
+
#
|
164
|
+
# prefix = IPAddress::Prefix32.new 24
|
165
|
+
#
|
166
|
+
# prefix.octets
|
167
|
+
# #=> [255, 255, 255, 0]
|
168
|
+
#
|
169
|
+
def octets
|
170
|
+
to_ip.split(".").map{|i| i.to_i}
|
171
|
+
end
|
172
|
+
|
173
|
+
#
|
174
|
+
# Unsigned 32 bits decimal number representing
|
175
|
+
# the prefix
|
176
|
+
#
|
177
|
+
# prefix = IPAddress::Prefix32.new 24
|
178
|
+
#
|
179
|
+
# prefix.to_u32
|
180
|
+
# #=> 4294967040
|
181
|
+
#
|
182
|
+
def to_u32
|
183
|
+
(IN4MASK >> host_prefix) << host_prefix
|
184
|
+
end
|
185
|
+
|
186
|
+
#
|
187
|
+
# Shortcut for the octecs in the dotted decimal
|
188
|
+
# representation
|
189
|
+
#
|
190
|
+
# prefix = IPAddress::Prefix32.new 24
|
191
|
+
#
|
192
|
+
# prefix[2]
|
193
|
+
# #=> 255
|
194
|
+
#
|
195
|
+
def [](index)
|
196
|
+
octets[index]
|
197
|
+
end
|
198
|
+
|
199
|
+
#
|
200
|
+
# The hostmask is the contrary of the subnet mask,
|
201
|
+
# as it shows the bits that can change within the
|
202
|
+
# hosts
|
203
|
+
#
|
204
|
+
# prefix = IPAddress::Prefix32.new 24
|
205
|
+
#
|
206
|
+
# prefix.hostmask
|
207
|
+
# #=> "0.0.0.255"
|
208
|
+
#
|
209
|
+
def hostmask
|
210
|
+
[~to_u32].pack("N").unpack("CCCC").join(".")
|
211
|
+
end
|
212
|
+
|
213
|
+
#
|
214
|
+
# Creates a new prefix by parsing a netmask in
|
215
|
+
# dotted decimal form
|
216
|
+
#
|
217
|
+
# prefix = IPAddress::Prefix32::parse_netmask "255.255.255.0"
|
218
|
+
# #=> 24
|
219
|
+
#
|
220
|
+
def self.parse_netmask(netmask)
|
221
|
+
octets = netmask.split(".").map{|i| i.to_i}
|
222
|
+
num = octets.pack("C"*octets.size).unpack("B*").first.count "1"
|
223
|
+
return self.new(num)
|
224
|
+
end
|
225
|
+
|
226
|
+
end # class Prefix32 < Prefix
|
227
|
+
|
228
|
+
class Prefix128 < Prefix
|
229
|
+
|
230
|
+
#
|
231
|
+
# Creates a new prefix object for 128 bits IPv6 addresses
|
232
|
+
#
|
233
|
+
# prefix = IPAddress::Prefix128.new 64
|
234
|
+
# #=> 64
|
235
|
+
#
|
236
|
+
def initialize(num=128)
|
237
|
+
unless (0..128).include? num.to_i
|
238
|
+
raise ArgumentError, "Prefix must be in range 0..128, got: #{num}"
|
239
|
+
end
|
240
|
+
super(num.to_i)
|
241
|
+
end
|
242
|
+
|
243
|
+
#
|
244
|
+
# Transforms the prefix into a string of bits
|
245
|
+
# representing the netmask
|
246
|
+
#
|
247
|
+
# prefix = IPAddress::Prefix128.new 64
|
248
|
+
#
|
249
|
+
# prefix.bits
|
250
|
+
# #=> "1111111111111111111111111111111111111111111111111111111111111111"
|
251
|
+
# "0000000000000000000000000000000000000000000000000000000000000000"
|
252
|
+
#
|
253
|
+
def bits
|
254
|
+
"1" * @prefix + "0" * (128 - @prefix)
|
255
|
+
end
|
256
|
+
|
257
|
+
#
|
258
|
+
# Unsigned 128 bits decimal number representing
|
259
|
+
# the prefix
|
260
|
+
#
|
261
|
+
# prefix = IPAddress::Prefix128.new 64
|
262
|
+
#
|
263
|
+
# prefix.to_u128
|
264
|
+
# #=> 340282366920938463444927863358058659840
|
265
|
+
#
|
266
|
+
def to_u128
|
267
|
+
bits.to_i(2)
|
268
|
+
end
|
269
|
+
|
270
|
+
#
|
271
|
+
# Returns the length of the host portion
|
272
|
+
# of a netmask.
|
273
|
+
#
|
274
|
+
# prefix = Prefix128.new 96
|
275
|
+
#
|
276
|
+
# prefix.host_prefix
|
277
|
+
# #=> 32
|
278
|
+
#
|
279
|
+
def host_prefix
|
280
|
+
128 - @prefix
|
281
|
+
end
|
282
|
+
|
283
|
+
end # class Prefix123 < Prefix
|
284
|
+
|
285
|
+
end # module IPAddress
|
data/lib/ipaddress_2.rb
ADDED
@@ -0,0 +1,293 @@
|
|
1
|
+
#
|
2
|
+
# = IPAddress
|
3
|
+
#
|
4
|
+
# A ruby library to manipulate IPv4 and IPv6 addresses
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Package:: IPAddress
|
8
|
+
# Author:: Marco Ceresa <ceresa@ieee.org>
|
9
|
+
# License:: Ruby License
|
10
|
+
#
|
11
|
+
#--
|
12
|
+
#
|
13
|
+
#++
|
14
|
+
|
15
|
+
require 'ipaddress_2/ipv4'
|
16
|
+
require 'ipaddress_2/ipv6'
|
17
|
+
require 'ipaddress_2/mongoid' if defined?(Mongoid)
|
18
|
+
|
19
|
+
module IPAddress
|
20
|
+
|
21
|
+
NAME = "IPAddress"
|
22
|
+
GEM = "ipaddress_2"
|
23
|
+
AUTHORS = ["Marco Ceresa <ceresa@ieee.org>"]
|
24
|
+
|
25
|
+
#
|
26
|
+
# Parse the argument string to create a new
|
27
|
+
# IPv4, IPv6 or Mapped IP object
|
28
|
+
#
|
29
|
+
# ip = IPAddress.parse 167837953 # 10.1.1.1
|
30
|
+
# ip = IPAddress.parse "172.16.10.1/24"
|
31
|
+
# ip6 = IPAddress.parse "2001:db8::8:800:200c:417a/64"
|
32
|
+
# ip_mapped = IPAddress.parse "::ffff:172.16.10.1/128"
|
33
|
+
#
|
34
|
+
# All the object created will be instances of the
|
35
|
+
# correct class:
|
36
|
+
#
|
37
|
+
# ip.class
|
38
|
+
# #=> IPAddress::IPv4
|
39
|
+
# ip6.class
|
40
|
+
# #=> IPAddress::IPv6
|
41
|
+
# ip_mapped.class
|
42
|
+
# #=> IPAddress::IPv6::Mapped
|
43
|
+
#
|
44
|
+
def IPAddress::parse(str)
|
45
|
+
|
46
|
+
# Check if an int was passed
|
47
|
+
if str.kind_of? Integer
|
48
|
+
return IPAddress::IPv4.new(ntoa(str))
|
49
|
+
end
|
50
|
+
|
51
|
+
case str
|
52
|
+
when /:.+\./
|
53
|
+
IPAddress::IPv6::Mapped.new(str)
|
54
|
+
when /\./
|
55
|
+
IPAddress::IPv4.new(str)
|
56
|
+
when /:/
|
57
|
+
IPAddress::IPv6.new(str)
|
58
|
+
else
|
59
|
+
raise ArgumentError, "Unknown IP Address #{str}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Converts a unit32 to IPv4
|
65
|
+
#
|
66
|
+
# IPAddress::ntoa(167837953)
|
67
|
+
# #-> "10.1.1.1"
|
68
|
+
#
|
69
|
+
def self.ntoa(uint)
|
70
|
+
unless(uint.is_a? Numeric and uint <= 0xffffffff and uint >= 0)
|
71
|
+
raise(::ArgumentError, "not a long integer: #{uint.inspect}")
|
72
|
+
end
|
73
|
+
ret = []
|
74
|
+
4.times do
|
75
|
+
ret.unshift(uint & 0xff)
|
76
|
+
uint >>= 8
|
77
|
+
end
|
78
|
+
ret.join('.')
|
79
|
+
end
|
80
|
+
|
81
|
+
#
|
82
|
+
# True if the object is an IPv4 address
|
83
|
+
#
|
84
|
+
# ip = IPAddress("192.168.10.100/24")
|
85
|
+
#
|
86
|
+
# ip.ipv4?
|
87
|
+
# #-> true
|
88
|
+
#
|
89
|
+
def ipv4?
|
90
|
+
self.kind_of? IPAddress::IPv4
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# True if the object is an IPv6 address
|
95
|
+
#
|
96
|
+
# ip = IPAddress("192.168.10.100/24")
|
97
|
+
#
|
98
|
+
# ip.ipv6?
|
99
|
+
# #-> false
|
100
|
+
#
|
101
|
+
def ipv6?
|
102
|
+
self.kind_of? IPAddress::IPv6
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
#
|
107
|
+
# Checks if the given string is either a valid IP, either a valid IPv4 subnet
|
108
|
+
#
|
109
|
+
# Example:
|
110
|
+
#
|
111
|
+
# IPAddress::valid? "10.0.0.0/24"
|
112
|
+
# #=> true
|
113
|
+
#
|
114
|
+
# IPAddress::valid? "2002::1"
|
115
|
+
# #=> true
|
116
|
+
#
|
117
|
+
# IPAddress::valid? "10.0.0.256"
|
118
|
+
# #=> false
|
119
|
+
#
|
120
|
+
# IPAddress::valid? "10.0.0.0/999"
|
121
|
+
# #=> false
|
122
|
+
#
|
123
|
+
def self.valid?(addr)
|
124
|
+
valid_ip?(addr) || valid_ipv4_subnet?(addr) || valid_ipv6_subnet?(addr)
|
125
|
+
end
|
126
|
+
|
127
|
+
#
|
128
|
+
# Checks if the given string is a valid IP address,
|
129
|
+
# either IPv4 or IPv6
|
130
|
+
#
|
131
|
+
# Example:
|
132
|
+
#
|
133
|
+
# IPAddress::valid_ip? "2002::1"
|
134
|
+
# #=> true
|
135
|
+
#
|
136
|
+
# IPAddress::valid_ip? "10.0.0.256"
|
137
|
+
# #=> false
|
138
|
+
#
|
139
|
+
def self.valid_ip?(addr)
|
140
|
+
valid_ipv4?(addr) || valid_ipv6?(addr)
|
141
|
+
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Checks if the given string is a valid IPv4 subnet
|
145
|
+
#
|
146
|
+
# Example:
|
147
|
+
#
|
148
|
+
# IPAddress::valid_ipv4_subnet? "10.0.0.0/24"
|
149
|
+
# #=> true
|
150
|
+
#
|
151
|
+
# IPAddress::valid_ipv4_subnet? "10.0.0.0/255.255.255.0"
|
152
|
+
# #=> true
|
153
|
+
#
|
154
|
+
# IPAddress::valid_ipv4_subnet? "10.0.0.0/64"
|
155
|
+
# #=> false
|
156
|
+
#
|
157
|
+
def self.valid_ipv4_subnet?(addr)
|
158
|
+
ip, netmask = addr.split("/")
|
159
|
+
|
160
|
+
valid_ipv4?(ip) && (!(netmask =~ /\A([12]?\d|3[0-2])\z/).nil? || valid_ipv4_netmask?(netmask))
|
161
|
+
end
|
162
|
+
|
163
|
+
#
|
164
|
+
# Checks if the given string is a valid IPv6 subnet
|
165
|
+
#
|
166
|
+
# Example:
|
167
|
+
#
|
168
|
+
# IPAddress::valid_ipv6_subnet? "::/0"
|
169
|
+
# #=> true
|
170
|
+
#
|
171
|
+
# IPAddress::valid_ipv6_subnet? "dead:beef:cafe:babe::/64"
|
172
|
+
# #=> true
|
173
|
+
#
|
174
|
+
# IPAddress::valid_ipv6_subnet? "2001::1/129"
|
175
|
+
# #=> false
|
176
|
+
#
|
177
|
+
def self.valid_ipv6_subnet?(addr)
|
178
|
+
ip, netmask = addr.split("/")
|
179
|
+
|
180
|
+
netmask = Integer(netmask, 10)
|
181
|
+
|
182
|
+
valid_ipv6?(ip) && netmask >= 0 && netmask <= 128
|
183
|
+
rescue ArgumentError
|
184
|
+
false
|
185
|
+
end
|
186
|
+
|
187
|
+
#
|
188
|
+
# Checks if the given string is a valid IPv4 address
|
189
|
+
#
|
190
|
+
# Example:
|
191
|
+
#
|
192
|
+
# IPAddress::valid_ipv4? "2002::1"
|
193
|
+
# #=> false
|
194
|
+
#
|
195
|
+
# IPAddress::valid_ipv4? "172.16.10.1"
|
196
|
+
# #=> true
|
197
|
+
#
|
198
|
+
def self.valid_ipv4?(addr)
|
199
|
+
if /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/ =~ addr
|
200
|
+
return $~.captures.all? {|i| i.to_i < 256}
|
201
|
+
end
|
202
|
+
false
|
203
|
+
end
|
204
|
+
|
205
|
+
#
|
206
|
+
# Checks if the argument is a valid IPv4 netmask
|
207
|
+
# expressed in dotted decimal format.
|
208
|
+
#
|
209
|
+
# IPAddress.valid_ipv4_netmask? "255.255.0.0"
|
210
|
+
# #=> true
|
211
|
+
#
|
212
|
+
def self.valid_ipv4_netmask?(addr)
|
213
|
+
arr = addr.split(".").map{|i| i.to_i}.pack("CCCC").unpack("B*").first.scan(/01/)
|
214
|
+
arr.empty? && valid_ipv4?(addr)
|
215
|
+
rescue
|
216
|
+
return false
|
217
|
+
end
|
218
|
+
|
219
|
+
#
|
220
|
+
# Checks if the given string is a valid IPv6 address
|
221
|
+
#
|
222
|
+
# Example:
|
223
|
+
#
|
224
|
+
# IPAddress::valid_ipv6? "2002::1"
|
225
|
+
# #=> true
|
226
|
+
#
|
227
|
+
# IPAddress::valid_ipv6? "2002::DEAD::BEEF"
|
228
|
+
# #=> false
|
229
|
+
#
|
230
|
+
def self.valid_ipv6?(addr)
|
231
|
+
# https://gist.github.com/cpetschnig/294476
|
232
|
+
# http://forums.intermapper.com/viewtopic.php?t=452
|
233
|
+
return true if /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/ =~ addr
|
234
|
+
false
|
235
|
+
end
|
236
|
+
|
237
|
+
#
|
238
|
+
# Deprecate method
|
239
|
+
#
|
240
|
+
def self.deprecate(message = nil) # :nodoc:
|
241
|
+
message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
|
242
|
+
warn("DEPRECATION WARNING: #{message}")
|
243
|
+
end
|
244
|
+
|
245
|
+
end # module IPAddress
|
246
|
+
|
247
|
+
#
|
248
|
+
# IPAddress is a wrapper method built around
|
249
|
+
# IPAddress's library classes. Its purpouse is to
|
250
|
+
# make you indipendent from the type of IP address
|
251
|
+
# you're going to use.
|
252
|
+
#
|
253
|
+
# For example, instead of creating the three types
|
254
|
+
# of IP addresses using their own contructors
|
255
|
+
#
|
256
|
+
# ip = IPAddress::IPv4.new "172.16.10.1/24"
|
257
|
+
# ip6 = IPAddress::IPv6.new "2001:db8::8:800:200c:417a/64"
|
258
|
+
# ip_mapped = IPAddress::IPv6::Mapped "::ffff:172.16.10.1/128"
|
259
|
+
#
|
260
|
+
# you can just use the IPAddress wrapper:
|
261
|
+
#
|
262
|
+
# ip = IPAddress "172.16.10.1/24"
|
263
|
+
# ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
|
264
|
+
# ip_mapped = IPAddress "::ffff:172.16.10.1/128"
|
265
|
+
#
|
266
|
+
# All the object created will be instances of the
|
267
|
+
# correct class:
|
268
|
+
#
|
269
|
+
# ip.class
|
270
|
+
# #=> IPAddress::IPv4
|
271
|
+
# ip6.class
|
272
|
+
# #=> IPAddress::IPv6
|
273
|
+
# ip_mapped.class
|
274
|
+
# #=> IPAddress::IPv6::Mapped
|
275
|
+
#
|
276
|
+
def IPAddress(str)
|
277
|
+
IPAddress::parse str
|
278
|
+
end
|
279
|
+
|
280
|
+
#
|
281
|
+
# Compatibility with Ruby 1.8
|
282
|
+
#
|
283
|
+
if RUBY_VERSION =~ /^1\.8/
|
284
|
+
class Hash # :nodoc:
|
285
|
+
alias :key :index
|
286
|
+
end
|
287
|
+
module Math # :nodoc:
|
288
|
+
def Math.log2(n)
|
289
|
+
log(n) / log(2)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|