construqt-ipaddress 0.8.1

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