construqt-ipaddress 0.8.1

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 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
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
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
+