ipaddress_2 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|