construqt-ipaddress 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/CHANGELOG.rdoc +105 -0
- data/LICENSE +20 -0
- data/README.rdoc +965 -0
- data/Rakefile +83 -0
- data/VERSION +1 -0
- data/ipaddress.gemspec +55 -0
- data/lib/ipaddress.rb +306 -0
- data/lib/ipaddress/ipv4.rb +1005 -0
- data/lib/ipaddress/ipv6.rb +1003 -0
- data/lib/ipaddress/prefix.rb +265 -0
- data/test/ipaddress/ipv4_test.rb +555 -0
- data/test/ipaddress/ipv6_test.rb +448 -0
- data/test/ipaddress/prefix_test.rb +159 -0
- data/test/ipaddress_test.rb +119 -0
- data/test/test_helper.rb +28 -0
- metadata +66 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 04be42104b879a022922e0c6ac872b848d749ea4
|
4
|
+
data.tar.gz: 25540b3bc8c8a45b4234425dfcafb2650cad8317
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ccef0969cab6e482ea78c65465f3a7b4d2b8cf1caadc1950c72a44fe3c9816f8b6ba648ac6635a1bc7935d42b9f9a76ece73e51bf866601cd9659cbd846abca8
|
7
|
+
data.tar.gz: 55d74b6ff30f5f0415401ddf130633e4e68496972689b61793c723f2496fb759184ec3b128aebff363f24a3ace56775e1bb91ce24e08bbc2c0645a06e3785e82
|
data/.document
ADDED
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
== ipaddress 0.9.0
|
2
|
+
|
3
|
+
CHANGED:: ipaddress now uses this[https://gist.github.com/cpetschnig/294476] regexp to validate IPv6 addresses. Thanks to Christoph Petschnig for his regexp and to Bronislav Robenek for fixing this.
|
4
|
+
|
5
|
+
|
6
|
+
== ipaddress 0.8.0
|
7
|
+
|
8
|
+
CHANGED:: Removed extension methods and extension directory to facilitate integration with the stdlib
|
9
|
+
CHANGED:: Reworked IPv4#<=>, now intuitively sorts objects based on the prefix
|
10
|
+
CHANGED:: IPv4#supernet now returns "0.0.0.0/0" if supernetting with a prefix less than 1
|
11
|
+
CHANGED:: IPv4#subnet now accept a new prefix instead of number of subnets (as per RFC3531)
|
12
|
+
NEW:: IPv6#network
|
13
|
+
NEW:: Prefix128#host_prefix
|
14
|
+
NEW:: IPv6#broadcast_u128
|
15
|
+
NEW:: IPv6#each
|
16
|
+
NEW:: IPv6#<=>
|
17
|
+
NEW:: IPv4#split
|
18
|
+
|
19
|
+
== ipaddress 0.7.5
|
20
|
+
|
21
|
+
CHANGED:: IPAddress::IPv4#each_host to improve speed
|
22
|
+
FIXED:: IPAddress::IPv4::summarize bug (summarization should now work properly)
|
23
|
+
NEW:: IPAddress::IPv4#include_all?
|
24
|
+
NEW:: #ipv4? and #ipv6?
|
25
|
+
|
26
|
+
== ipaddress 0.7.0
|
27
|
+
|
28
|
+
NEW:: IPAddress::IPv6#include?
|
29
|
+
NEW:: IPAddress::IPv6#network_u128
|
30
|
+
NEW:: Modified IPAddress::IPv6::Mapped to accept IPv4 mapped addresses in IPv6 format
|
31
|
+
NEW:: IPAddress::IPv4#private?
|
32
|
+
NEW:: IPAddress::IPv4::parse_classful
|
33
|
+
|
34
|
+
== ipaddress 0.6.0
|
35
|
+
|
36
|
+
=== API changes
|
37
|
+
* IPv4#to_s now returns the address portion only,
|
38
|
+
to retain compatibility with IPAddr. Example:
|
39
|
+
|
40
|
+
IPAddress("172.16.10.1/24").to_s
|
41
|
+
#=> "172.16.10.1" # ipaddress 0.6.0
|
42
|
+
|
43
|
+
IPAddress("172.16.10.1/24").to_s
|
44
|
+
#=> "172.16.10.1/24" # ipaddress 0.5.0
|
45
|
+
|
46
|
+
* IPv6#to_s now returns the address portion only,
|
47
|
+
to retain compatibility with IPAddr. Example:
|
48
|
+
|
49
|
+
IPAddress "2001:db8::8:800:200c:417a/64".to_s
|
50
|
+
#=> "2001:db8::8:800:200c:417a" # ipaddress 0.6.0
|
51
|
+
|
52
|
+
IPAddress "2001:db8::8:800:200c:417a/64".to_s
|
53
|
+
#=> "2001:db8::8:800:200c:417a/64" # ipaddress 0.6.0
|
54
|
+
|
55
|
+
* IPv6::Unspecified#to_s, IPv6::Loopback and
|
56
|
+
IPv6::Mapped#to_s now return the address portion only,
|
57
|
+
to retain compatibility with IPAddr.
|
58
|
+
* IPv4::summarize now returns an array even if the
|
59
|
+
result is a single subnet, to keep consistency
|
60
|
+
and avoid confusion
|
61
|
+
|
62
|
+
=== New methods
|
63
|
+
* IPv4#to_string and IPv6#to_string: print the address
|
64
|
+
with the prefix portion, like the #to_s method in
|
65
|
+
ipaddress 0.5.0
|
66
|
+
* IPAddress::parse, for those who don't like the wrapper
|
67
|
+
method IPAddress()
|
68
|
+
* IPv6#to_string_uncompressed, returns a string with the
|
69
|
+
uncompressed IPv6 and the prefix
|
70
|
+
* IPv6::Mapped#to_string, returns the IPv6 Mapped address
|
71
|
+
with IPv4 notation and the prefix
|
72
|
+
* IPv6#reverse, returns the ip6.arpa DNS reverse lookup
|
73
|
+
string
|
74
|
+
* IPv4#arpa and IPv6#arpa, alias of the respective #reverse
|
75
|
+
methods
|
76
|
+
* Prefix#+, Prefix#-
|
77
|
+
|
78
|
+
=== Library structure
|
79
|
+
* Moved all the IPAddress module methods from
|
80
|
+
lib/ipaddress/ipbase.rb to lib/ipaddress.rb
|
81
|
+
* Removed IPBase superclass
|
82
|
+
* IPv4 and IPv6 classes no longer inherit from IPBase
|
83
|
+
* Removed lib/ipaddress/ipbase.rb
|
84
|
+
* Removed test/ipaddress/ipbase_test.rb
|
85
|
+
|
86
|
+
=== Minor fixes
|
87
|
+
* Replaced Ruby 1.9 deprecated Hash#index with Hash#key
|
88
|
+
* Removed require ruby-prof from tests which was causing
|
89
|
+
users to install ruby-prof or manually remove the line
|
90
|
+
* Removed "must" method from tests, replaced by normal
|
91
|
+
Test::Unit methods
|
92
|
+
* Removed duplicate Jeweler entry in Rakefile
|
93
|
+
* Made Integer#closest_power_of_2 more general by adding
|
94
|
+
an optional limit parameter
|
95
|
+
* Fixed summarization algorithm (thanks to nicolas fevrier)
|
96
|
+
* Fixed bug in prefix_from_ip (thanks to jdpace)
|
97
|
+
|
98
|
+
=== Documentation
|
99
|
+
* Normalized README rdoc headers
|
100
|
+
* Added documentation for IPAddress::Prefix
|
101
|
+
* Added documentation for IPAddress::IPv4 and
|
102
|
+
IPAddress::IPv6
|
103
|
+
* Fixed formatting
|
104
|
+
* Fixed lots of typos
|
105
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009-2011 Marco Ceresa,Meno Abels
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,965 @@
|
|
1
|
+
== <b>IPAddress 1.0 is currently under development and will be released soon! Stay tuned!</b>
|
2
|
+
|
3
|
+
---
|
4
|
+
|
5
|
+
= IPAddress
|
6
|
+
|
7
|
+
IPAddress is a Ruby library designed to make the use of IPv4 and IPv6
|
8
|
+
addresses simple, powerful and enjoyable. It provides a complete set of
|
9
|
+
methods to handle IP addresses for any need, from simple scripting to
|
10
|
+
full network design.
|
11
|
+
|
12
|
+
IPAddress is written with a full OO interface, and its code is easy to
|
13
|
+
read, maintain and extend. The documentation is full of examples, to
|
14
|
+
let you start being productive immediately.
|
15
|
+
|
16
|
+
This document provides a brief introduction to the library and
|
17
|
+
examples of typical usage.
|
18
|
+
|
19
|
+
== Requirements
|
20
|
+
|
21
|
+
* Ruby >= 1.8.7 (not tested with previous versions)
|
22
|
+
* Ruby 1.9.2 or later is strongly recommended
|
23
|
+
|
24
|
+
IPAddress 0.8.0 has been tested on:
|
25
|
+
|
26
|
+
* ruby-1.8.7-p334 [ i386 ]
|
27
|
+
* ree-1.8.7-2011.03 [ i386 ]
|
28
|
+
* rbx-head [ ]
|
29
|
+
* jruby-1.6.1 [ linux-i386-java ]
|
30
|
+
* ruby-1.9.1-p431 [ i386 ]
|
31
|
+
* ruby-1.9.2-p180 [ i386 ]
|
32
|
+
|
33
|
+
If you want to collaborate feel
|
34
|
+
free to send a small report to my email address, or
|
35
|
+
{join the discussion}[http://groups.google.com/group/ruby-ipaddress].
|
36
|
+
|
37
|
+
|
38
|
+
== Installation
|
39
|
+
|
40
|
+
Install the library using rubygems
|
41
|
+
|
42
|
+
$ gem install ipaddress
|
43
|
+
|
44
|
+
You can then use it in your programs:
|
45
|
+
|
46
|
+
require 'rubygems' # optional
|
47
|
+
require 'ipaddress'
|
48
|
+
|
49
|
+
Another way would be to clone the git repository
|
50
|
+
|
51
|
+
$ git clone git://github.com/bluemonk/ipaddress.git
|
52
|
+
|
53
|
+
And then install the library
|
54
|
+
|
55
|
+
$ cd ipaddress
|
56
|
+
ipaddress$ rake install
|
57
|
+
|
58
|
+
== Documentation
|
59
|
+
|
60
|
+
The code is fully documented with RDoc. You can generate the
|
61
|
+
documentation with Rake:
|
62
|
+
|
63
|
+
ipaddress$ rake rdoc
|
64
|
+
|
65
|
+
The latest documentation can be found online at
|
66
|
+
{this address}[http://rubydoc.info/gems/ipaddress/0.8.0/frames]
|
67
|
+
|
68
|
+
== IPv4
|
69
|
+
|
70
|
+
Class IPAddress::IPv4 is used to handle IPv4 type addresses. IPAddress
|
71
|
+
is similar to other IP Addresses libraries, like Ruby's own
|
72
|
+
IPAddr. However it works slightly different, as we will see.
|
73
|
+
|
74
|
+
=== Create a new IPv4 address
|
75
|
+
|
76
|
+
The usual way to express an IP Address is using its dotted decimal
|
77
|
+
form, such as 172.16.10.1, and a prefix, such as 24, separated by a
|
78
|
+
slash.
|
79
|
+
|
80
|
+
172.16.10.1/24
|
81
|
+
|
82
|
+
To create a new IPv4 object, you can use IPv4 own class
|
83
|
+
|
84
|
+
ip = IPAddress::IPv4.new "172.16.10.1/24"
|
85
|
+
|
86
|
+
or, in a easier way, using the IPAddress parse method
|
87
|
+
|
88
|
+
ip = IPAddress.parse "172.16.10.1/24"
|
89
|
+
|
90
|
+
which accepts and parses any kind of IP (IPv4, IPV6 and
|
91
|
+
IPv4 IPv6 Mapped addresses).
|
92
|
+
|
93
|
+
If you like syntactic sugar, you can use the wrapper method
|
94
|
+
IPAddress(), which is built around IPAddress::parse:
|
95
|
+
|
96
|
+
ip = IPAddress "172.16.10.1/24"
|
97
|
+
|
98
|
+
You can specify an IPv4 address in any of two ways:
|
99
|
+
|
100
|
+
IPAddress "172.16.10.1/24"
|
101
|
+
IPAddress "172.16.10.1/255.255.255.0"
|
102
|
+
|
103
|
+
In this example, prefix /24 and netmask 255.255.255.0 are the same and
|
104
|
+
you have the flexibility to use either one of them.
|
105
|
+
|
106
|
+
If you don't explicitly specify the prefix (or the subnet mask),
|
107
|
+
IPAddress thinks you're dealing with host addresses and not with
|
108
|
+
networks. Therefore, the default prefix will be /32, or
|
109
|
+
255.255.255.255. For example:
|
110
|
+
|
111
|
+
# let's declare an host address
|
112
|
+
host = IPAddress::IPv4.new "10.1.1.1"
|
113
|
+
|
114
|
+
puts host.to_string
|
115
|
+
#=> "10.1.1.1/32"
|
116
|
+
|
117
|
+
The new created object has prefix /32, which is the same
|
118
|
+
as we created the following:
|
119
|
+
|
120
|
+
host = IPAddress::IPv4.new "10.1.1.1/32"
|
121
|
+
|
122
|
+
=== Handling the IPv4 address
|
123
|
+
|
124
|
+
Once created, you can obtain the attributes for an IPv4 object:
|
125
|
+
|
126
|
+
ip = IPAddress("172.16.10.1/24")
|
127
|
+
|
128
|
+
ip.address
|
129
|
+
#=> "172.16.10.1"
|
130
|
+
ip.prefix
|
131
|
+
#=> 24
|
132
|
+
|
133
|
+
In case you need to retrieve the netmask in IPv4 format, you can use
|
134
|
+
the IPv4#netmask method:
|
135
|
+
|
136
|
+
ip.netmask
|
137
|
+
#=> "255.255.255.0"
|
138
|
+
|
139
|
+
A special attribute, IPv4#octets, is available to get the four
|
140
|
+
decimal octets from the IP address:
|
141
|
+
|
142
|
+
ip.octets
|
143
|
+
#=> [172,16,10,1]
|
144
|
+
|
145
|
+
Shortcut method IPv4#[], provides access to a given octet whithin the
|
146
|
+
range:
|
147
|
+
|
148
|
+
ip[1]
|
149
|
+
#=> 16
|
150
|
+
|
151
|
+
If you need to print out the IPv4 address in a canonical form, you can
|
152
|
+
use IPv4#to_string
|
153
|
+
|
154
|
+
ip.to_string
|
155
|
+
#=> "172.16.10.l/24"
|
156
|
+
|
157
|
+
=== Changing netmask
|
158
|
+
|
159
|
+
You can set a new prefix (netmask) after creating an IPv4
|
160
|
+
object. For example:
|
161
|
+
|
162
|
+
ip.prefix = 25
|
163
|
+
|
164
|
+
ip.to_string
|
165
|
+
#=> "172.16.10.l/25"
|
166
|
+
|
167
|
+
If you need to use a netmask in IPv4 format, you can achive so by
|
168
|
+
using the IPv4#netmask= method
|
169
|
+
|
170
|
+
ip.netmask = "255.255.255.252"
|
171
|
+
|
172
|
+
ip.to_string
|
173
|
+
#=> "172.16.10.1/30"
|
174
|
+
|
175
|
+
=== Working with networks, broadcasts and addresses
|
176
|
+
|
177
|
+
Some very important topics in dealing with IP addresses are the
|
178
|
+
concepts of +network+ and +broadcast+, as well as the addresses
|
179
|
+
included in a range.
|
180
|
+
|
181
|
+
When you specify an IPv4 address such as "172.16.10.1/24", you are
|
182
|
+
actually handling two different information:
|
183
|
+
|
184
|
+
* The IP address itself, "172.16.10.1"
|
185
|
+
* The subnet mask which indicates the network
|
186
|
+
|
187
|
+
The network number is the IP which has all zeroes in the host
|
188
|
+
portion. In our example, because the prefix is 24, we identify our
|
189
|
+
network number to have the last 8 (32-24) bits all zeroes. Thus, IP
|
190
|
+
address "172.16.10.1/24" belongs to network "172.16.10.0/24".
|
191
|
+
|
192
|
+
This is very important because, for instance, IP "172.16.10.1/16" is
|
193
|
+
very different to the previous one, belonging to the very different
|
194
|
+
network "172.16.0.0/16".
|
195
|
+
|
196
|
+
==== Networks
|
197
|
+
|
198
|
+
With IPAddress it's very easy to calculate the network for an IP
|
199
|
+
address:
|
200
|
+
|
201
|
+
ip = IPAddress "172.16.10.1/24"
|
202
|
+
|
203
|
+
net = ip.network
|
204
|
+
#=> #<IPAddress::IPv4:0xb7a5ab24 @octets=[172, 16, 10, 0],
|
205
|
+
@prefix=24,
|
206
|
+
@address="172.16.10.0">
|
207
|
+
net.to_string
|
208
|
+
#=> "172.16.10.0/24"
|
209
|
+
|
210
|
+
Method IPv4#network creates a new IPv4 object from the network
|
211
|
+
number, calculated after the original object. We want to outline here
|
212
|
+
that the network address is a perfect legitimate IPv4 address, which
|
213
|
+
just happen to have all zeroes in the host portion.
|
214
|
+
|
215
|
+
You can use method IPv4#network? to check whether an IP address is a
|
216
|
+
network or not:
|
217
|
+
|
218
|
+
ip1 = IPAddress "172.16.10.1/24"
|
219
|
+
ip2 = IPAddress "172.16.10.4/30"
|
220
|
+
|
221
|
+
ip1.network?
|
222
|
+
#=> false
|
223
|
+
ip2.network?
|
224
|
+
#=> true
|
225
|
+
|
226
|
+
==== Broadcast
|
227
|
+
|
228
|
+
The broadcast address is the contrary than the network number: where
|
229
|
+
the network number has all zeroes in the host portion, the broadcast
|
230
|
+
address has all one's. For example, ip "172.16.10.1/24" has broadcast
|
231
|
+
"172.16.10.255/24", where ip "172.16.10.1/16" has broadcast
|
232
|
+
"172.16.255.255/16".
|
233
|
+
|
234
|
+
Method IPv4#broadcast has the same behavior as is #network
|
235
|
+
counterpart: it creates a new IPv4 object to handle the broadcast
|
236
|
+
address:
|
237
|
+
|
238
|
+
ip = IPAddress "172.16.10.1/24"
|
239
|
+
|
240
|
+
bcast = ip.broadcast
|
241
|
+
#=> #<IPAddress::IPv4:0xb7a406fc @octets=[172, 16, 10, 255],
|
242
|
+
@prefix=24,
|
243
|
+
@address="172.16.10.255">
|
244
|
+
bcast.to_string
|
245
|
+
#=> "172.16.10.255/24"
|
246
|
+
|
247
|
+
==== Addresses, ranges and iterators
|
248
|
+
|
249
|
+
So we see that the netmask essentially specifies a range for IP
|
250
|
+
addresses that are included in a network: all the addresses between
|
251
|
+
the network number and the broadcast. IPAddress has many methods to
|
252
|
+
iterate between those addresses. Let's start with IPv4#each, which
|
253
|
+
iterates over all addresses in a range
|
254
|
+
|
255
|
+
ip = IPAddress "172.16.10.1/24"
|
256
|
+
|
257
|
+
ip.each do |addr|
|
258
|
+
puts addr
|
259
|
+
end
|
260
|
+
|
261
|
+
It is important to note that it doesn't matter if the original IP is a
|
262
|
+
host IP or a network number (or a broadcast address): the #each method
|
263
|
+
only considers the range that the original IP specifies.
|
264
|
+
|
265
|
+
If you only want to iterate over hosts IP, use the IPv4#each_host
|
266
|
+
method:
|
267
|
+
|
268
|
+
ip = IPAddress "172.16.10.1/24"
|
269
|
+
|
270
|
+
ip.each_host do |host|
|
271
|
+
puts host
|
272
|
+
end
|
273
|
+
|
274
|
+
Methods IPv4#first and IPv4#last return a new object containing
|
275
|
+
respectively the first and the last host address in the range
|
276
|
+
|
277
|
+
ip = IPAddress "172.16.10.100/24"
|
278
|
+
|
279
|
+
ip.first.to_string
|
280
|
+
#=> "172.16.10.1/24"
|
281
|
+
|
282
|
+
ip.last.to_string
|
283
|
+
#=> "172.16.10.254/24"
|
284
|
+
|
285
|
+
=== IP special formats
|
286
|
+
|
287
|
+
The IPAddress library provides a complete set of methods to access an
|
288
|
+
IPv4 address in special formats, such as binary, 32 bits unsigned int,
|
289
|
+
data and hexadecimal.
|
290
|
+
|
291
|
+
Let's take the following IPv4 as an example:
|
292
|
+
|
293
|
+
ip = IPAddress "172.16.10.1/24"
|
294
|
+
|
295
|
+
ip.address
|
296
|
+
#=> "172.16.10.1"
|
297
|
+
|
298
|
+
The first thing to highlight here is that all these conversion methods
|
299
|
+
only take into consideration the address portion of an IPv4 object and
|
300
|
+
not the prefix (netmask).
|
301
|
+
|
302
|
+
So, to express the address in binary format, use the IPv4#bits method:
|
303
|
+
|
304
|
+
ip.bits
|
305
|
+
#=> "10101100000100000000101000000001"
|
306
|
+
|
307
|
+
To calculate the 32 bits unsigned int format of the ip address, use
|
308
|
+
the IPv4#to_u32 method
|
309
|
+
|
310
|
+
ip.to_u32
|
311
|
+
#=> 2886732289
|
312
|
+
|
313
|
+
This method is the equivalent of the Unix call pton(), expressing an
|
314
|
+
IP address in the so called +network byte order+ notation. However, if
|
315
|
+
you want to transmit your IP over a network socket, you might need to
|
316
|
+
transform it in data format using the IPv4#data method:
|
317
|
+
|
318
|
+
ip.data
|
319
|
+
#=> "\254\020\n\001"
|
320
|
+
|
321
|
+
Finally, you can transform an IPv4 address into a format which is
|
322
|
+
suitable to use in IPv4-IPv6 mapped addresses:
|
323
|
+
|
324
|
+
ip.to_ipv6
|
325
|
+
#=> "ac10:0a01"
|
326
|
+
|
327
|
+
=== Classful networks
|
328
|
+
|
329
|
+
IPAddress allows you to create and manipulate objects using the old
|
330
|
+
and deprecated (but apparently still popular) classful networks concept.
|
331
|
+
|
332
|
+
Classful networks and addresses don't have a prefix: their subnet mask
|
333
|
+
is univocally identified by their address, and therefore diveded in classes.
|
334
|
+
As per RFC 791, these classes are:
|
335
|
+
|
336
|
+
* Class A, from 0.0.0.0 to 127.255.255.255
|
337
|
+
* Class B, from 128.0.0.0 to 191.255.255.255
|
338
|
+
* Class C, from 192.0.0.0 to 255.255.255.255
|
339
|
+
|
340
|
+
Since classful networks here are only considered to calculate the default
|
341
|
+
prefix number, classes D and E are not considered.
|
342
|
+
|
343
|
+
To create a classful IP and prefix from an IP address, use the
|
344
|
+
IPv4::parse_classful method:
|
345
|
+
|
346
|
+
# classful ip
|
347
|
+
ip = IPAddress::IPv4::parse_classful "10.1.1.1"
|
348
|
+
|
349
|
+
ip.prefix
|
350
|
+
#=> 8
|
351
|
+
|
352
|
+
The method automatically created a new IPv4 object and assigned it
|
353
|
+
the correct prefix.
|
354
|
+
|
355
|
+
You can easily check which CLASSFUL network an IPv4 object belongs:
|
356
|
+
|
357
|
+
ip = IPAddress("10.0.0.1/24")
|
358
|
+
ip.a?
|
359
|
+
#=> true
|
360
|
+
|
361
|
+
ip = IPAddress("172.16.10.1/24")
|
362
|
+
ip.b?
|
363
|
+
#=> true
|
364
|
+
|
365
|
+
ip = IPAddress("192.168.1.1/30")
|
366
|
+
ip.c?
|
367
|
+
#=> true
|
368
|
+
|
369
|
+
Remember that these methods are only checking the address portion of an IP, and are
|
370
|
+
independent from its prefix, as classful networks have no concept of prefix.
|
371
|
+
|
372
|
+
For more information on CLASSFUL networks visit the
|
373
|
+
{Wikipedia page}[http://en.wikipedia.org/wiki/Classful_network]
|
374
|
+
|
375
|
+
=== Network design with IPAddress
|
376
|
+
|
377
|
+
IPAddress includes a lot of useful methods to manipulate IPv4 and IPv6
|
378
|
+
networks and do some basic network design.
|
379
|
+
|
380
|
+
==== Subnetting
|
381
|
+
|
382
|
+
The process of subnetting is the division of a network into smaller
|
383
|
+
(in terms of hosts capacity) networks, called subnets, so that they
|
384
|
+
all share a common root, which is the starting network.
|
385
|
+
|
386
|
+
For example, if you have network "172.16.10.0/24", we can subnet it
|
387
|
+
into 4 smaller subnets. The new prefix will be /26, because 4 is 2^2
|
388
|
+
and therefore we add 2 bits to the network prefix (24+2=26).
|
389
|
+
|
390
|
+
Subnetting is easy with IPAddress. You actually have two options:
|
391
|
+
|
392
|
+
* IPv4#subnet: specify a new prefix
|
393
|
+
* IPv4#split: tell IPAddress how many subnets you want to create.
|
394
|
+
|
395
|
+
Let's examine IPv4#subnet first. Say you have network "172.16.10.0/24"
|
396
|
+
and you want to subnet it into /26 networks. With IPAddress it's very
|
397
|
+
easy:
|
398
|
+
|
399
|
+
network = IPAddress "172.16.10.0/24"
|
400
|
+
|
401
|
+
subnets = network.subnet(26)
|
402
|
+
|
403
|
+
subnets.map{|i| i.to_string}
|
404
|
+
#=> ["172.16.10.0/26",
|
405
|
+
"172.16.10.64/26",
|
406
|
+
"172.16.10.128/26",
|
407
|
+
"172.16.10.192/26"]
|
408
|
+
|
409
|
+
As you can see, an Array has been created, containing 4 new IPv4 objects
|
410
|
+
representing the new subnets.
|
411
|
+
|
412
|
+
Another way to create subnets is to tell IPAddress how many subnets you'd
|
413
|
+
like to have, and letting the library calculate the new prefix for you.
|
414
|
+
|
415
|
+
Let's see how it works, using IPv4#split method. Say you want 4 new subnets:
|
416
|
+
|
417
|
+
network = IPAddress("172.16.10.0/24")
|
418
|
+
|
419
|
+
subnets = network.split(4)
|
420
|
+
|
421
|
+
subnets.map{|i| i.to_string}
|
422
|
+
#=> ["172.16.10.0/26",
|
423
|
+
"172.16.10.64/26",
|
424
|
+
"172.16.10.128/26",
|
425
|
+
"172.16.10.192/26"]
|
426
|
+
|
427
|
+
Hey, that's the same result as before! This actually makes sense, as the
|
428
|
+
two operations are complementary. When you use IPv4#subnet with the new
|
429
|
+
prefix, IPAddress will always create a number of subnets that is a power
|
430
|
+
of two. This is equivalent to use IPv4#split with a power of 2.
|
431
|
+
|
432
|
+
Where IPv4#split really shines is with the so called "uneven subnetting".
|
433
|
+
You are not limited to split a network into a power-of-two numbers of
|
434
|
+
subnets: IPAddress lets you create any number of subnets, and it will
|
435
|
+
try to organize the new created network in the best possible way, making
|
436
|
+
an efficent allocation of the space.
|
437
|
+
|
438
|
+
An example here is worth a thousand words. Let's use the same network
|
439
|
+
as the previous examples:
|
440
|
+
|
441
|
+
network = IPAddress("172.16.10.0/24")
|
442
|
+
|
443
|
+
How do we split this network into 3 subnets? Very easy:
|
444
|
+
|
445
|
+
subnets = network.split(3)
|
446
|
+
|
447
|
+
subnets.map{|i| i.to_string}
|
448
|
+
#=> ["172.16.10.0/26",
|
449
|
+
"172.16.10.64/26",
|
450
|
+
"172.16.10.128/25"]
|
451
|
+
|
452
|
+
As you can see, IPAddress tried to perform a good allocation by filling up
|
453
|
+
all the address space from the original network. There is no point in splitting
|
454
|
+
a network into 3 subnets like "172.16.10.0/26", "172.16.10.64/26" and
|
455
|
+
"172.16.10.128/26", as you would end up having "172.16.10.192/26" wasted (plus,
|
456
|
+
I suppose I wouldn't need a Ruby library to perform un-efficient IP
|
457
|
+
allocation, as I do that myself very well ;) ).
|
458
|
+
|
459
|
+
We can go even further and split into 11 subnets:
|
460
|
+
|
461
|
+
network.split(11)
|
462
|
+
#=> ["172.16.10.0/28", "172.16.10.16/28", "172.16.10.32/28",
|
463
|
+
"172.16.10.48/28", "172.16.10.64/28", "172.16.10.80/28",
|
464
|
+
"172.16.10.96/28", "172.16.10.112/28", "172.16.10.128/27",
|
465
|
+
"172.16.10.160/27", "172.16.10.192/26"]
|
466
|
+
|
467
|
+
As you can see, most of the networks are /28, with a few /27 and one
|
468
|
+
/26 to fill up the remaining space.
|
469
|
+
|
470
|
+
==== Summarization
|
471
|
+
|
472
|
+
Summarization (or aggregation) is the process when two or more
|
473
|
+
networks are taken together to check if a supernet, including
|
474
|
+
all and only these networks, exists. If it exists then this supernet
|
475
|
+
is called the summarized (or aggregated) network.
|
476
|
+
It is very important to understand that summarization can only
|
477
|
+
occur if there are no holes in the aggregated network, or, in
|
478
|
+
other words, if the given networks fill completely the address space
|
479
|
+
of the supernet. So the two rules are:
|
480
|
+
|
481
|
+
1) The aggregate network must contain +all+ the IP addresses of the
|
482
|
+
original networks;
|
483
|
+
|
484
|
+
2) The aggregate network must contain +only+ the IP addresses of the
|
485
|
+
original networks;
|
486
|
+
|
487
|
+
A few examples will help clarify the above. Let's consider for
|
488
|
+
instance the following two networks:
|
489
|
+
|
490
|
+
ip1 = IPAddress("172.16.10.0/24")
|
491
|
+
ip2 = IPAddress("172.16.11.0/24")
|
492
|
+
|
493
|
+
These two networks can be expressed using only one IP address
|
494
|
+
network if we change the prefix. Let Ruby do the work:
|
495
|
+
|
496
|
+
IPAddress::IPv4::summarize(ip1,ip2).map(&:to_string)
|
497
|
+
#=> "172.16.10.0/23"
|
498
|
+
|
499
|
+
We note how the network "172.16.10.0/23" includes all the
|
500
|
+
addresses specified in the above networks, and (more important) includes
|
501
|
+
ONLY those addresses.
|
502
|
+
|
503
|
+
If we summarized +ip1+ and +ip2+ with the following network:
|
504
|
+
|
505
|
+
"172.16.0.0/16"
|
506
|
+
|
507
|
+
we would have satisfied rule #1 above, but not rule #2. So
|
508
|
+
|
509
|
+
"172.16.0.0/16"
|
510
|
+
|
511
|
+
is not an aggregate network for +ip1+ and +ip2+.
|
512
|
+
|
513
|
+
If it's not possible to compute a single aggregated network for
|
514
|
+
all the original networks, the method returns an array with all the
|
515
|
+
aggregate networks found. For example, the following four networks can be
|
516
|
+
aggregated in a single /22:
|
517
|
+
|
518
|
+
ip1 = IPAddress("10.0.0.1/24")
|
519
|
+
ip2 = IPAddress("10.0.1.1/24")
|
520
|
+
ip3 = IPAddress("10.0.2.1/24")
|
521
|
+
ip4 = IPAddress("10.0.3.1/24")
|
522
|
+
|
523
|
+
IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
|
524
|
+
#=> ["10.0.0.0/22"]
|
525
|
+
|
526
|
+
But the following networks can't be summarized in a single
|
527
|
+
network:
|
528
|
+
|
529
|
+
ip1 = IPAddress("10.0.1.1/24")
|
530
|
+
ip2 = IPAddress("10.0.2.1/24")
|
531
|
+
ip3 = IPAddress("10.0.3.1/24")
|
532
|
+
ip4 = IPAddress("10.0.4.1/24")
|
533
|
+
|
534
|
+
IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
|
535
|
+
#=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
|
536
|
+
|
537
|
+
In this case, the two summarizables networks have been aggregated into
|
538
|
+
a single /23, while the other two networks have been left untouched.
|
539
|
+
|
540
|
+
==== Supernetting
|
541
|
+
|
542
|
+
Supernetting is a different operation than aggregation, as it only
|
543
|
+
works on a single network and returns a new single IPv4 object,
|
544
|
+
representing the supernet.
|
545
|
+
|
546
|
+
Supernetting is similar to subnetting, except that you getting as a
|
547
|
+
result a network with a smaller prefix (bigger host space). For
|
548
|
+
example, given the network
|
549
|
+
|
550
|
+
ip = IPAddress("172.16.10.0/24")
|
551
|
+
|
552
|
+
you can supernet it with a new /23 prefix
|
553
|
+
|
554
|
+
ip.supernet(23).to_string
|
555
|
+
#=> "172.16.10.0/23"
|
556
|
+
|
557
|
+
However if you supernet it with a /22 prefix, the network address will
|
558
|
+
change:
|
559
|
+
|
560
|
+
ip.supernet(22).to_string
|
561
|
+
#=> "172.16.8.0/22"
|
562
|
+
|
563
|
+
This is because "172.16.10.0/22" is not a network anymore, but an host
|
564
|
+
address.
|
565
|
+
|
566
|
+
== IPv6
|
567
|
+
|
568
|
+
IPAddress is not only fantastic for IPv4 addresses, it's also great to
|
569
|
+
handle IPv6 addresses family! Let's discover together how to use it in
|
570
|
+
our projects.
|
571
|
+
|
572
|
+
=== IPv6 addresses
|
573
|
+
|
574
|
+
IPv6 addresses are 128 bits long, in contrast with IPv4 addresses
|
575
|
+
which are only 32 bits long. An IPv6 address is generally written as
|
576
|
+
eight groups of four hexadecimal digits, each group representing 16
|
577
|
+
bits or two octet. For example, the following is a valid IPv6
|
578
|
+
address:
|
579
|
+
|
580
|
+
2001:0db8:0000:0000:0008:0800:200c:417a
|
581
|
+
|
582
|
+
Letters in an IPv6 address are usually written downcase, as per
|
583
|
+
RFC. You can create a new IPv6 object using uppercase letters, but
|
584
|
+
they will be converted.
|
585
|
+
|
586
|
+
==== Compression
|
587
|
+
|
588
|
+
Since IPv6 addresses are very long to write, there are some
|
589
|
+
simplifications and compressions that you can use to shorten them.
|
590
|
+
|
591
|
+
* Leading zeroes: all the leading zeroes within a group can be
|
592
|
+
omitted: "0008" would become "8"
|
593
|
+
|
594
|
+
* A string of consecutive zeroes can be replaced by the string
|
595
|
+
"::". This can be only applied once.
|
596
|
+
|
597
|
+
Using compression, the IPv6 address written above can be shorten into
|
598
|
+
the following, equivalent, address
|
599
|
+
|
600
|
+
2001:db8::8:800:200c:417a
|
601
|
+
|
602
|
+
This short version is often used in human representation.
|
603
|
+
|
604
|
+
==== Network Mask
|
605
|
+
|
606
|
+
As we used to do with IPv4 addresses, an IPv6 address can be written
|
607
|
+
using the prefix notation to specify the subnet mask:
|
608
|
+
|
609
|
+
2001:db8::8:800:200c:417a/64
|
610
|
+
|
611
|
+
The /64 part means that the first 64 bits of the address are
|
612
|
+
representing the network portion, and the last 64 bits are the host
|
613
|
+
portion.
|
614
|
+
|
615
|
+
=== Using IPAddress with IPv6 addresses
|
616
|
+
|
617
|
+
All the IPv6 representations we've just seen are perfectly fine when
|
618
|
+
you want to create a new IPv6 address:
|
619
|
+
|
620
|
+
ip6 = IPAddress "2001:0db8:0000:0000:0008:0800:200C:417A"
|
621
|
+
|
622
|
+
ip6 = IPAddress "2001:db8:0:0:8:800:200C:417A"
|
623
|
+
|
624
|
+
ip6 = IPAddress "2001:db8:8:800:200C:417A"
|
625
|
+
|
626
|
+
All three are giving out the same IPv6 object. The default subnet mask
|
627
|
+
for an IPv6 is 128, as IPv6 addresses don't have classes like IPv4
|
628
|
+
addresses. If you want a different mask, you can go ahead and explicit
|
629
|
+
it:
|
630
|
+
|
631
|
+
ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
|
632
|
+
|
633
|
+
Access the address portion and the prefix by using the respective
|
634
|
+
methods:
|
635
|
+
|
636
|
+
ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
|
637
|
+
|
638
|
+
ip6.address
|
639
|
+
#=> "2001:0db8:0000:0000:0008:0800:200c:417a"
|
640
|
+
|
641
|
+
ip6.prefix
|
642
|
+
#=> 64
|
643
|
+
|
644
|
+
A compressed version of the IPv6 address can be obtained with the
|
645
|
+
IPv6#compressed method:
|
646
|
+
|
647
|
+
ip6 = IPAddress "2001:0db8:0000:0000:0008:200c:417a:00ab/64"
|
648
|
+
|
649
|
+
ip6.compressed
|
650
|
+
#=> "2001:db8::8:800:200c:417a"
|
651
|
+
|
652
|
+
=== Handling the IPv6 address
|
653
|
+
|
654
|
+
Accessing the groups that form an IPv6 address is very easy with the
|
655
|
+
IPv6#groups method:
|
656
|
+
|
657
|
+
ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
|
658
|
+
|
659
|
+
ip6.groups
|
660
|
+
#=> [8193, 3512, 0, 0, 8, 2048, 8204, 16762]
|
661
|
+
|
662
|
+
As with IPv4 addresses, each individual group can be accessed using
|
663
|
+
the IPv6#[] shortcut method:
|
664
|
+
|
665
|
+
ip6[0]
|
666
|
+
#=> 8193
|
667
|
+
ip6[1]
|
668
|
+
#=> 3512
|
669
|
+
ip6[2]
|
670
|
+
#=> 0
|
671
|
+
ip6[3]
|
672
|
+
#=> 0
|
673
|
+
|
674
|
+
Note that each 16 bits group is expressed in its decimal form. You can
|
675
|
+
also obtain the groups into hexadecimal format using the IPv6#hexs
|
676
|
+
method:
|
677
|
+
|
678
|
+
ip6.hexs
|
679
|
+
#=> => ["2001", "0db8", "0000", "0000", "0008", "0800", "200c", "417a"]
|
680
|
+
|
681
|
+
A few other methods are available to transform an IPv6 address into
|
682
|
+
decimal representation, with IPv6.to_i
|
683
|
+
|
684
|
+
ip6.to_i
|
685
|
+
#=> 42540766411282592856906245548098208122
|
686
|
+
|
687
|
+
or to hexadecimal representation
|
688
|
+
|
689
|
+
ip6.to_hex
|
690
|
+
#=> "20010db80000000000080800200c417a"
|
691
|
+
|
692
|
+
To print out an IPv6 address in human readable form, use the IPv6#to_s, IPv6#to_string
|
693
|
+
and IPv6#to_string_uncompressed methods
|
694
|
+
|
695
|
+
ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
|
696
|
+
|
697
|
+
ip6.to_string
|
698
|
+
#=> "2001:db8::8:800:200c:417a/96"
|
699
|
+
|
700
|
+
ip6.to_string_uncompressed
|
701
|
+
#=> "2001:0db8:0000:0000:0008:0800:200c:417a/96"
|
702
|
+
|
703
|
+
As you can see, IPv6.to_string prints out the compressed form, while
|
704
|
+
IPv6.to_string_uncompressed uses the expanded version.
|
705
|
+
|
706
|
+
==== Compressing and uncompressing
|
707
|
+
|
708
|
+
If you have a string representing an IPv6 address, you can easily
|
709
|
+
compress it and uncompress it using the two class methods IPv6::expand
|
710
|
+
and IPv6::compress.
|
711
|
+
|
712
|
+
For example, let's say you have the following uncompressed IPv6
|
713
|
+
address:
|
714
|
+
|
715
|
+
ip6str = "2001:0DB8:0000:CD30:0000:0000:0000:0000"
|
716
|
+
|
717
|
+
Here is the compressed version:
|
718
|
+
|
719
|
+
IPAddress::IPv6.compress ip6str
|
720
|
+
#=> "2001:db8:0:cd30::"
|
721
|
+
|
722
|
+
The other way works as well:
|
723
|
+
|
724
|
+
ip6str = "2001:db8:0:cd30::"
|
725
|
+
|
726
|
+
IPAddress::IPv6.expand ip6str
|
727
|
+
#=> "2001:0DB8:0000:CD30:0000:0000:0000:0000"
|
728
|
+
|
729
|
+
These methods can be used when you don't want to create a new object
|
730
|
+
just for expanding or compressing an address (although a new object is
|
731
|
+
actually created internally).
|
732
|
+
|
733
|
+
=== New IPv6 address from other formats
|
734
|
+
|
735
|
+
You can create a new IPv6 address from different formats than just a
|
736
|
+
string representing the colon-hex groups.
|
737
|
+
|
738
|
+
For instance, if you have a data stream, you can use IPv6::parse_data,
|
739
|
+
like in the following example:
|
740
|
+
|
741
|
+
data = " \001\r\270\000\000\000\000\000\b\b\000 \fAz"
|
742
|
+
|
743
|
+
ip6 = IPAddress::IPv6::parse_data data
|
744
|
+
ip6.prefix = 64
|
745
|
+
|
746
|
+
ip6.to_string
|
747
|
+
#=> "2001:db8::8:800:200c:417a/64"
|
748
|
+
|
749
|
+
A new IPv6 address can also be created from an unsigned 128 bits
|
750
|
+
integer:
|
751
|
+
|
752
|
+
u128 = 42540766411282592856906245548098208122
|
753
|
+
|
754
|
+
ip6 = IPAddress::IPv6::parse_u128 u128
|
755
|
+
ip6.prefix = 64
|
756
|
+
|
757
|
+
ip6.to_string
|
758
|
+
#=>"2001:db8::8:800:200c:417a/64"
|
759
|
+
|
760
|
+
Finally, a new IPv6 address can be created from an hex string:
|
761
|
+
|
762
|
+
hex = "20010db80000000000080800200c417a"
|
763
|
+
|
764
|
+
ip6 = IPAddress::IPv6::parse_hex hex
|
765
|
+
ip6.prefix = 64
|
766
|
+
|
767
|
+
ip6.to_string
|
768
|
+
#=> "2001:db8::8:800:200c:417a/64"
|
769
|
+
|
770
|
+
=== Special IPv6 addresses
|
771
|
+
|
772
|
+
Some IPv6 have a special meaning and are expressed in a special form,
|
773
|
+
quite different than an usual IPv6 address. IPAddress has built-in
|
774
|
+
support for unspecified, loopback and mapped IPv6 addresses.
|
775
|
+
|
776
|
+
==== Unspecified address
|
777
|
+
|
778
|
+
The address with all zero bits is called the +unspecified+ address
|
779
|
+
(corresponding to 0.0.0.0 in IPv4). It should be something like this:
|
780
|
+
|
781
|
+
0000:0000:0000:0000:0000:0000:0000:0000
|
782
|
+
|
783
|
+
but, with the use of compression, it is usually written as just two
|
784
|
+
colons:
|
785
|
+
|
786
|
+
::
|
787
|
+
|
788
|
+
or, specifying the netmask:
|
789
|
+
|
790
|
+
::/128
|
791
|
+
|
792
|
+
With IPAddress, create a new unspecified IPv6 address using its own
|
793
|
+
subclass:
|
794
|
+
|
795
|
+
ip = IPAddress::IPv6::Unspecified.new
|
796
|
+
|
797
|
+
ip.to_string
|
798
|
+
#=> "::/128"
|
799
|
+
|
800
|
+
You can easily check if an IPv6 object is an unspecified address by
|
801
|
+
using the IPv6#unspecified? method
|
802
|
+
|
803
|
+
ip.unspecified?
|
804
|
+
#=> true
|
805
|
+
|
806
|
+
An unspecified IPv6 address can also be created with the wrapper
|
807
|
+
method, like we've seen before
|
808
|
+
|
809
|
+
ip = IPAddress "::"
|
810
|
+
|
811
|
+
ip.unspecified?
|
812
|
+
#=> true
|
813
|
+
|
814
|
+
This address must never be assigned to an interface and is to be used
|
815
|
+
only in software before the application has learned its host's source
|
816
|
+
address appropriate for a pending connection. Routers must not forward
|
817
|
+
packets with the unspecified address.
|
818
|
+
|
819
|
+
==== Loopback address
|
820
|
+
|
821
|
+
The loopback address is a unicast localhost address. If an
|
822
|
+
application in a host sends packets to this address, the IPv6 stack
|
823
|
+
will loop these packets back on the same virtual interface.
|
824
|
+
|
825
|
+
Loopback addresses are expressed in the following form:
|
826
|
+
|
827
|
+
::1
|
828
|
+
|
829
|
+
or, with their appropriate prefix,
|
830
|
+
|
831
|
+
::1/128
|
832
|
+
|
833
|
+
As for the unspecified addresses, IPv6 loopbacks can be created with
|
834
|
+
IPAddress calling their own class:
|
835
|
+
|
836
|
+
ip = IPAddress::IPv6::Loopback.new
|
837
|
+
|
838
|
+
ip.to_string
|
839
|
+
#=> "::1/128"
|
840
|
+
|
841
|
+
or by using the wrapper:
|
842
|
+
|
843
|
+
ip = IPAddress "::1"
|
844
|
+
|
845
|
+
ip.to_string
|
846
|
+
#=> "::1/128"
|
847
|
+
|
848
|
+
Checking if an address is loopback is easy with the IPv6#loopback?
|
849
|
+
method:
|
850
|
+
|
851
|
+
ip.loopback?
|
852
|
+
#=> true
|
853
|
+
|
854
|
+
The IPv6 loopback address corresponds to 127.0.0.1 in IPv4.
|
855
|
+
|
856
|
+
==== Mapped address
|
857
|
+
|
858
|
+
It is usually identified as a IPv4 mapped IPv6 address, a particular
|
859
|
+
IPv6 address which aids the transition from IPv4 to IPv6. The
|
860
|
+
structure of the address is
|
861
|
+
|
862
|
+
::ffff:w.y.x.z
|
863
|
+
|
864
|
+
where w.x.y.z is a normal IPv4 address. For example, the following is
|
865
|
+
a mapped IPv6 address:
|
866
|
+
|
867
|
+
::ffff:192.168.100.1
|
868
|
+
|
869
|
+
IPAddress is very powerful in handling mapped IPv6 addresses, as the
|
870
|
+
IPv4 portion is stored internally as a normal IPv4 object. Let's have
|
871
|
+
a look at some examples. To create a new mapped address, just use the
|
872
|
+
class builder itself
|
873
|
+
|
874
|
+
ip6 = IPAddress::IPv6::Mapped.new "::ffff:172.16.10.1/128"
|
875
|
+
|
876
|
+
or just use the wrapper method
|
877
|
+
|
878
|
+
ip6 = IPAddress "::ffff:172.16.10.1/128"
|
879
|
+
|
880
|
+
Let's check it's really a mapped address:
|
881
|
+
|
882
|
+
ip6.mapped?
|
883
|
+
#=> true
|
884
|
+
|
885
|
+
ip6.to_string
|
886
|
+
#=> "::ffff:172.16.10.1/128"
|
887
|
+
|
888
|
+
Now with the +ipv4+ attribute, we can easily access the IPv4 portion
|
889
|
+
of the mapped IPv6 address:
|
890
|
+
|
891
|
+
ip6.ipv4.address
|
892
|
+
#=> "172.16.10.1"
|
893
|
+
|
894
|
+
Internally, the IPv4 address is stored as two 16 bits
|
895
|
+
groups. Therefore all the usual methods for an IPv6 address are
|
896
|
+
working perfectly fine:
|
897
|
+
|
898
|
+
ip6.to_hex
|
899
|
+
#=> "00000000000000000000ffffac100a01"
|
900
|
+
|
901
|
+
ip6.address
|
902
|
+
#=> "0000:0000:0000:0000:0000:ffff:ac10:0a01"
|
903
|
+
|
904
|
+
A mapped IPv6 can also be created just by specify the address in the
|
905
|
+
following format:
|
906
|
+
|
907
|
+
ip6 = IPAddress "::172.16.10.1"
|
908
|
+
|
909
|
+
That is, two colons and the IPv4 address. However, as by RFC, the ffff
|
910
|
+
group will be automatically added at the beginning
|
911
|
+
|
912
|
+
ip6.to_string
|
913
|
+
=> "::ffff:172.16.10.1/128"
|
914
|
+
|
915
|
+
making it a mapped IPv6 compatible address.
|
916
|
+
|
917
|
+
== Why not using IPAddr?
|
918
|
+
|
919
|
+
IPAddr is the IP addresses library that comes with Ruby standard
|
920
|
+
lib. We found this library, although very well written, not very
|
921
|
+
suitable for all our needs, and not very flexible.
|
922
|
+
|
923
|
+
Some quick examples of things you can't do with IPAddr:
|
924
|
+
|
925
|
+
* store both the address and the prefix information
|
926
|
+
* quickly find the broadcast address of a network
|
927
|
+
* iterate over hosts
|
928
|
+
* perform subnetting or network aggregation
|
929
|
+
|
930
|
+
Many methods and procedures are so old that they have been
|
931
|
+
declared deprecated by the IETF, and some others have bugs in their
|
932
|
+
implementation.
|
933
|
+
|
934
|
+
Moreover, IPAddress is more robust and is already around 50% faster than IPAddr,
|
935
|
+
in addition to provide an organic API with logical separation and OO structure.
|
936
|
+
|
937
|
+
We hope that IPAddress will address all these issues and meet all your
|
938
|
+
needs in network programming.
|
939
|
+
|
940
|
+
|
941
|
+
== Community
|
942
|
+
|
943
|
+
Want to join the community?
|
944
|
+
|
945
|
+
* {IPAddress google group}[http://groups.google.com/group/ruby-ipaddress]
|
946
|
+
|
947
|
+
We've created a group to discuss about
|
948
|
+
IPAddress future development, features and provide some kind of support.
|
949
|
+
Feel free to join us and tell us what you think!
|
950
|
+
|
951
|
+
== Thanks to
|
952
|
+
|
953
|
+
Thanks to Luca Russo (vargolo) and Simone Carletti
|
954
|
+
(weppos) for all the support and technical review. Thanks to Marco Beri,
|
955
|
+
Bryan T. Richardson, Nicolas Fevrier, jdpace, Daniele Alessandri, jrdioko,
|
956
|
+
Ghislain Charrier, Pawel Krzesniak, Mark Sullivan, Leif Gensert,
|
957
|
+
Erik Ahlström, Peter Vandenberk and Steve Rawlinson for their support,
|
958
|
+
feedback and bug reports.
|
959
|
+
|
960
|
+
== Copyright
|
961
|
+
|
962
|
+
Copyright (c) 2009-2011 Marco Ceresa. See LICENSE for details.
|
963
|
+
|
964
|
+
|
965
|
+
|