ipaddress 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ server.rb
7
+ ipaddr.html
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Marco Ceresa
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.
@@ -0,0 +1,866 @@
1
+ = IPAddress
2
+
3
+ IPAddress is a Ruby library designed to make the use of IPv4 and IPv6
4
+ addresses easy, powerful and enjoyable. It provides a complete set of
5
+ methods to handle IP addresses for any need, from simple scripting to
6
+ full network design.
7
+
8
+ IPAddress is written with a full OO interface, and its code is easy to
9
+ read, maintain and extend. The documentation is full of examples, to
10
+ let you start being productive immediately.
11
+
12
+ This document provides a brief introduction to the library and
13
+ examples of typical usage.
14
+
15
+ === Why not using IPAddr?
16
+
17
+ IPAddr is the IP addresses library that comes with Ruby standard
18
+ lib. We found this library, although very well written, not very
19
+ suitable for all our needs, and not very flexible.
20
+
21
+ Some quick examples of things you can't do with IPAddr:
22
+
23
+ * store both the address and the prefix information
24
+ * quickly find the broadcast address of a network
25
+ * iterate over hosts
26
+ * perform subnetting or network aggregation
27
+
28
+ We hope that IPAddress will address all these issues and meet all your
29
+ needs in network programming.
30
+
31
+ = Installation
32
+
33
+ Install the library using rubygems
34
+
35
+ $ gem install ipaddress
36
+
37
+ You can then use it in your programs:
38
+
39
+ require 'rubygems' # optional
40
+ require 'ipaddress'
41
+
42
+ Another way would be to clone the git repository
43
+
44
+ $ git clone git://github.com/bluemonk/net-dns.git
45
+
46
+ And then install the library
47
+
48
+ $ cd ipaddress
49
+ ipaddress$ rake install
50
+
51
+ = Documentation
52
+
53
+ The code is fully documented with RDoc. You can generate the
54
+ documentation with Rake:
55
+
56
+ ipaddress$ rake rdoc
57
+
58
+ The latest documentation can be found online at the following address
59
+
60
+ http://marcoceresa.com/ipaddress
61
+
62
+ = Usage
63
+
64
+ In this section I will illustrate how to use the IPAddress library
65
+ through some examples of common tasks.
66
+
67
+ == IPv4
68
+
69
+ Class IPAddress::IPv4 is used to handle IPv4 type addresses. IPAddress
70
+ is similar to other IP Addresses libraries, like Ruby's own
71
+ IPAddr. However it works slightly different, as we will see.
72
+
73
+ === Create a new IPv4 address
74
+
75
+ The usual way to express an IP Address is using its dotted decimal
76
+ form, such as 172.16.10.1, and a prefix, such as 24, separated by a
77
+ slash.
78
+
79
+ 172.16.10.1/24
80
+
81
+ To create a new IPv4 object, you can use IPv4 own class
82
+
83
+ ip = IPAddress::IPv4.new "172.16.10.1/24"
84
+
85
+ or, in a easier way, using the IPAddress wrapper method
86
+
87
+ ip = IPAddress "172.16.10.1/24"
88
+
89
+ You can specify an IPv4 address in any of two ways:
90
+
91
+ IPAddress "172.16.10.1/24"
92
+ IPAddress "172.16.10.1/255.255.255.0"
93
+
94
+ In this example, prefix /24 and netmask 255.255.255.0 are the same and
95
+ you have the flexibility to use either one of them.
96
+
97
+ === Classful networks
98
+
99
+ If you don't specify a prefix (or a subnet mask), then the library
100
+ will create an object base on the CLASSFUL network from the given
101
+ IP. Remember the CLASSFUL network are the following (RFC 791)
102
+
103
+ * Class A, from 0.0.0.0 to 127.255.255.255
104
+ * Class B, from 128.0.0.0 to 191.255.255.255
105
+ * Class C, from 192.0.0.0 to 255.255.255.255
106
+
107
+ Since classful networks here are only considered to calculate the default
108
+ prefix number, classes D and E are not considered.
109
+
110
+ You can easily check which CLASSFUL network the IP belongs:
111
+
112
+ ip = IPAddress("10.0.0.1/24")
113
+ ip.a?
114
+ #=> true
115
+
116
+ ip = IPAddress("172.16.10.1/24")
117
+ ip.b?
118
+ #=> true
119
+
120
+ ip = IPAddress("192.168.1.1/30")
121
+ ip.c?
122
+ #=> true
123
+
124
+ These methods are only checking the address portion of an IP, and are
125
+ indipendent from its prefix.
126
+
127
+ For more information on CLASSFUL networks visit the following
128
+ Wikipedia page: http://en.wikipedia.org/wiki/Classful_network
129
+
130
+ === Handling the IPv4 address
131
+
132
+ Once created, you can obtain the attributes for an IPv4 object:
133
+
134
+ ip = IPAddress("172.16.10.1/24")
135
+
136
+ ip.address
137
+ #=> "172.16.10.1"
138
+ ip.prefix
139
+ #=> 24
140
+
141
+ In case you need to retrieve the netmask in IPv4 format, you can use
142
+ the IPv4#netmask method:
143
+
144
+ ip.netmask
145
+ #=> "255.255.255.0"
146
+
147
+ A special attribute, IPv4#octets, is available to get the four
148
+ decimal octets from the IP address:
149
+
150
+ ip.octets
151
+ #=> [172,16,10,1]
152
+
153
+ Shortcut method IPv4#[], provides access to a given octet whithin the
154
+ range:
155
+
156
+ ip[1]
157
+ #=> 16
158
+
159
+ If you need to print out the IPv4 address in a canonical form, you can
160
+ use IPv4#to_s
161
+
162
+ ip.to_s
163
+ #=> "172.16.10.l/24"
164
+
165
+ === Changing netmask
166
+
167
+ You can set a new prefix (netmask) after creating an IPv4
168
+ object. For example:
169
+
170
+ ip.prefix = 25
171
+ ip.to_s
172
+ #=> "172.16.10.l/25"
173
+
174
+ If you need to use a netmask in IPv4 format, you can achive so by
175
+ using the IPv4#netmask= method
176
+
177
+ ip.netmask = "255.255.255.252"
178
+ ip.to_s
179
+ #=> "172.16.10.1/30"
180
+
181
+ === Working with networks, broadcasts and addresses
182
+
183
+ Some very important topics in dealing with IP addresses are the
184
+ concepts of +network+ and +broadcast+, as well as the addresses
185
+ included in a range.
186
+
187
+ When you specify an IPv4 address such as "172.16.10.1/24", you are
188
+ actually handling two different information:
189
+
190
+ * The IP address itself, "172.16.10.1"
191
+ * The subnet mask which indicates the network
192
+
193
+ The network number is the IP which has all zeroes in the host
194
+ portion. In our example, because the prefix is 24, we identify our
195
+ network number to have the last 8 (32-24) bits all zeroes. Thus, IP
196
+ address "172.16.10.1/24" belongs to network "172.16.10.0/24".
197
+
198
+ This is very important because, for instance, IP "172.16.10.1/16" is
199
+ very different to the previous one, belonging to the very different
200
+ network "172.16.0.0/16".
201
+
202
+ With IPAddress it's very easy to calculate the network for an IP
203
+ address:
204
+
205
+ ip = IPAddress "172.16.10.1/24"
206
+ net = ip.network
207
+ #=> #<IPAddress::IPv4:0xb7a5ab24 @octets=[172, 16, 10, 0],
208
+ @prefix=24,
209
+ @address="172.16.10.0">
210
+ net.to_s
211
+ #=> "172.16.10.0/24"
212
+
213
+ The IPv4#network method creates a new IPv4 object from the network
214
+ number, calculated after the original object. We want to outline here
215
+ that the network address is a perfect legitimate IPv4 address, which
216
+ just happen to have all zeroes in the host portion.
217
+
218
+ You can use method IPv4#network? to check whether an IP address is a
219
+ network or not:
220
+
221
+ ip1 = IPAddress "172.16.10.1/24"
222
+ ip2 = IPAddress "172.16.10.4/30"
223
+
224
+ ip1.network?
225
+ #=> false
226
+ ip2.network?
227
+ #=> true
228
+
229
+ The broadcast address is the contrary than the network number: where
230
+ the network number has all zeroes in the host portion, the broadcast
231
+ address has all one's. For example, ip "172.16.10.1/24" has broadcast
232
+ "172.16.10.255/24", where ip "172.16.10.1/16" has broadcast
233
+ "172.16.255.255/16".
234
+
235
+ Method IPv4#broadcast has the same behaviour as is #network
236
+ counterpart: it creates a new IPv4 object to handle the broadcast
237
+ address:
238
+
239
+ ip = IPAddress "172.16.10.1/24"
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_s
245
+ #=> "172.16.10.255/24"
246
+
247
+ So we see that the netmask essentially specifies a range for IP
248
+ addresses that are included in a network: all the addresses between
249
+ the network number and the broadcast. IPAddress has many methods to
250
+ iterate between those addresses. Let's start with IPv4#each, which
251
+ iterates over all addresses in a range
252
+
253
+ ip = IPAddress "172.16.10.1/24"
254
+
255
+ ip.each do |addr|
256
+ puts addr
257
+ end
258
+
259
+ It is important to note that it doesn't matter if the original IP is a
260
+ host IP or a network number (or a broadcast address): the #each method
261
+ only considers the range that the original IP specifies.
262
+
263
+ If you only want to iterate over hosts IP, use the Ipv4#each_host
264
+ method:
265
+
266
+ ip = IPAddress "172.16.10.1/24"
267
+
268
+ ip.each_host do |host|
269
+ puts host
270
+ end
271
+
272
+ Methods IPv4#first and IPv4#last return a new object containing
273
+ respectively the first and the last host address in the range
274
+
275
+ ip = IPAddress "172.16.10.100/24"
276
+
277
+ ip.first.to_s
278
+ #=> "172.16.10.1/24"
279
+
280
+ ip.last.to_s
281
+ #=> "172.16.10.254/24"
282
+
283
+ === IP special formats
284
+
285
+ The IPAddress library provides a complete set of methods to access an
286
+ IPv4 address in special formats, such as binary, 32 bits unsigned int,
287
+ data and hexadecimal.
288
+
289
+ Let's take the following IPv4 as an example:
290
+
291
+ ip = IPAddress "172.16.10.1/24"
292
+ ip.address
293
+ #=> "172.16.10.1"
294
+
295
+ The first thing to highlight here is that all these conversion methods
296
+ only take into consideration the address portion of an IPv4 object and
297
+ not the prefix (netmask).
298
+
299
+ So, to express the address in binary format, use the IPv4#bits method:
300
+
301
+ ip.bits
302
+ #=> "10101100000100000000101000000001"
303
+
304
+ To calculate the 32 bits unsigned int format of the ip address, use
305
+ the IPv4#to_u32 method
306
+
307
+ ip.to_u32
308
+ #=> 2886732289
309
+
310
+ This method is the equivalent of the Unix call pton(), expressing an
311
+ IP address in the so called +network byte order+ notation. However, if
312
+ you want to trasmit your IP over a network socket, you might need to
313
+ transform it in data format using the IPv4#data method:
314
+
315
+ ip.data
316
+ #=> "\254\020\n\001"
317
+
318
+ Finally, you can transform an IPv4 address into a format which is
319
+ suitable to use in IPv4-IPv6 mapped addresses:
320
+
321
+ ip.to_ipv6
322
+ #=> "ac10:0a01"
323
+
324
+
325
+ == Network design with IPAddress
326
+
327
+ IPAddress includes a lot of useful methods to manipulate IPv4 and IPv6
328
+ networks and do some basic network design.
329
+
330
+ === Subnetting
331
+
332
+ The process of subnetting is the division of a network into smaller
333
+ (in terms of hosts capacity) networks, called subnets, so that they
334
+ all share a common root, which is the starting network.
335
+
336
+ For example, if you have network "172.16.10.0/24", we can subnet it
337
+ into 4 smaller subnets. The new prefix will be /26, because 4 is 2^2
338
+ and therefore we add 2 bits to the network prefix (24+2=26).
339
+
340
+ Subnetting is easy with IPAddress. Let's work out the last example:
341
+
342
+ network = IPAddress("172.16.10.0/24")
343
+
344
+ subnets = network / 4
345
+ #=> [#<IPAddress::IPv4:0xb7b10e10 @octets=[172,16,10,0] [...]
346
+ #<IPAddress::IPv4:0xb7b0f1b4 @octets=[172,16,10,64] [...]
347
+ #<IPAddress::IPv4:0xb7b0e5ac @octets=[172,16,10,128] [...]
348
+ #<IPAddress::IPv4:0xb7b0e0c0 @octets=[172,16,10,192] [...]]
349
+
350
+ subnets.map{|i| i.to_s}
351
+ #=> ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26",
352
+ "172.16.10.192/26"]
353
+
354
+ You can also use method IPv4#subnets, which is an alias for
355
+ IPv4#/. Please note that you don't have to specify a network to
356
+ calculate a subnet: if the IPv4 object is a host IPv4, the method will
357
+ calculate the network number for that network and then subnet it. For
358
+ example:
359
+
360
+ ip = IPAddress("172.16.10.58/24")
361
+
362
+ ip.subnet(4).map{|i| i.to_s}
363
+ #=> ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26",
364
+ "172.16.10.192/26"]
365
+
366
+ Usually, subnetting implies dividing a network to a number of subnets
367
+ which is a power of two: in this way, you can be sure that the network
368
+ will be divived evenly, and all the subnets will have the same number
369
+ of hosts.
370
+
371
+ === Uneven subnetting
372
+
373
+ IPAddress also handles un-even subnetting: if you specify any number
374
+ (up to the prefix limit), the network will be divided so that the
375
+ first power-of-two networks will be even, and all the rest will just
376
+ fill out the space.
377
+
378
+ As an example, let's divide network 172.16.10.0/24 into 3 different subnets:
379
+
380
+ network = IPAddress("172.16.10.0/24")
381
+ network.subnet(3).map{|i| i.to_s}
382
+ #=> ["172.16.10.0/26",
383
+ "172.16.10.64/26",
384
+ "172.16.10.128/25"]
385
+
386
+ We can go even further and divide into 11 subnets:
387
+
388
+ network = IPAddress("172.16.10.0/24")
389
+ network.subnet(11).map{|i| i.to_s}
390
+ #=> ["172.16.10.0/28", "172.16.10.16/28", "172.16.10.32/28",
391
+ "172.16.10.48/28", "172.16.10.64/28", "172.16.10.80/28",
392
+ "172.16.10.96/28", "172.16.10.112/28", "172.16.10.128/27",
393
+ "172.16.10.160/27", "172.16.10.192/26"]
394
+
395
+ As you can see, most of the networks are /28, with a few /27 and one
396
+ /26 to fill up the remaning space.
397
+
398
+ === Summarization
399
+
400
+ Summarization (or aggregation) is the process when two or more
401
+ networks are taken together to check if a supernet, including
402
+ all and only these networks, exists. If it exists then this supernet
403
+ is called the summarized (or aggregated) network.
404
+ It is very important to understand that summarization can only
405
+ occur if there are no holes in the aggregated network, or, in
406
+ other words, if the given networks fill completely the address space
407
+ of the supernet. So the two rules are:
408
+
409
+ 1) The aggregate network must contain +all+ the IP addresses of the
410
+ original networks;
411
+ 2) The aggregate network must contain +only+ the IP addresses of the
412
+ original networks;
413
+
414
+ A few examples will help clarify the above. Let's consider for
415
+ instance the following two networks:
416
+
417
+ ip1 = IPAddress("172.16.10.0/24")
418
+ ip2 = IPAddress("172.16.11.0/24")
419
+
420
+ These two networks can be expressed using only one IP address
421
+ network if we change the prefix. Let Ruby do the work:
422
+
423
+ IPAddress::IPv4::summarize(ip1,ip2).to_s
424
+ #=> "172.16.10.0/23"
425
+
426
+ We note how the network "172.16.10.0/23" includes all the
427
+ addresses specified in the above networks, and (more important) includes
428
+ ONLY those addresses.
429
+
430
+ If we summarized +ip1+ and +ip2+ with the following network:
431
+
432
+ "172.16.0.0/16"
433
+
434
+ we would have satisfied rule #1 above, but not rule #2. So
435
+
436
+ "172.16.0.0/16"
437
+
438
+ is not an aggregate network for +ip1+ and +ip2+.
439
+
440
+ If it's not possible to compute a single aggregated network for
441
+ all the original networks, the method returns an array with all the
442
+ aggregate networks found. For example, the following four networks can be
443
+ aggregated in a single /22:
444
+
445
+ ip1 = IPAddress("10.0.0.1/24")
446
+ ip2 = IPAddress("10.0.1.1/24")
447
+ ip3 = IPAddress("10.0.2.1/24")
448
+ ip4 = IPAddress("10.0.3.1/24")
449
+
450
+ IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).to_s
451
+ #=> "10.0.0.0/22",
452
+
453
+ But the following networks can't be summarized in a single
454
+ network:
455
+
456
+ ip1 = IPAddress("10.0.1.1/24")
457
+ ip2 = IPAddress("10.0.2.1/24")
458
+ ip3 = IPAddress("10.0.3.1/24")
459
+ ip4 = IPAddress("10.0.4.1/24")
460
+ IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_s}
461
+ #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
462
+
463
+ In this case, the two summarizables networks have been aggregated into
464
+ a single /23, while the other two networks have been left untouched.
465
+
466
+ === Supernetting
467
+
468
+ Supernetting is a different operation than aggregation, as it only
469
+ works on a single network and returns a new single IPv4 object,
470
+ representing the supernet.
471
+
472
+ Supernetting is similar to subnetting, except that you getting as a
473
+ result a network with a smaller prefix (bigger host space). For
474
+ example, given the network
475
+
476
+ ip = IPAddress("172.16.10.0/24")
477
+
478
+ you can supernet it with a new /23 prefix
479
+
480
+ ip.supernet(23).to_s
481
+ #=> "172.16.10.0/23"
482
+
483
+ However if you supernet it with a /22 prefix, the network address will
484
+ change:
485
+
486
+ ip.supernet(22).to_s
487
+ #=> "172.16.8.0/22"
488
+
489
+ This is because "172.16.10.0/22" is not a network anymore, but an host
490
+ address.
491
+
492
+
493
+ =IPv6
494
+
495
+ IPAddress is not only fantastic for IPv4 addresses, it's also great to
496
+ handle IPv6 addresses family! Let's discover together how to use it in
497
+ our projects.
498
+
499
+ == IPv6 addresses
500
+
501
+ IPv6 addresses are 128 bits long, in contrast with IPv4 addresses
502
+ which are only 32 bits long. An IPv6 address is generally written as
503
+ eight groups of four hexadecimal digits, each group representing 16
504
+ bits or two octect. For example, the following is a valid IPv6
505
+ address:
506
+
507
+ 1080:0000:0000:0000:0008:0800:200c:417a
508
+
509
+ Letters in an IPv6 address are usually written downcase, as per
510
+ RFC. You can create a new IPv6 object using uppercase letters, but
511
+ they will be converted.
512
+
513
+ === Compression
514
+
515
+ Since IPv6 addresses are very long to write, there are some
516
+ semplifications and compressions that you can use to shorten them.
517
+
518
+ * Leading zeroes: all the leading zeroes within a group can be
519
+ omitted: "0008" would become "8"
520
+
521
+ * A string of consecutive zeroes can be replaced by the string
522
+ "::". This can be only applied once.
523
+
524
+ Using compression, the IPv6 address written above can be shorten into
525
+ the following, equivalent, address
526
+
527
+ 1080::8:800:200c:417a
528
+
529
+ This short version is often used in human representation.
530
+
531
+ === Network Mask
532
+
533
+ As we used to do with IPv4 addresses, an IPv6 address can be written
534
+ using the prefix notation to specify the subnet mask:
535
+
536
+ 1080::8:800:200c:417a/64
537
+
538
+ The /64 part means that the first 64 bits of the address are
539
+ representing the network portion, and the last 64 bits are the host
540
+ portion.
541
+
542
+ == Using IPAddress with IPv6 addresses
543
+
544
+ All the IPv6 representations we've just seen are perfectly fine when
545
+ you want to create a new IPv6 address:
546
+
547
+ ip6 = IPAddress "1080:0000:0000:0000:0008:0800:200C:417A"
548
+
549
+ ip6 = IPAddress "1080:0:0:0:8:800:200C:417A"
550
+
551
+ ip6 = IPAddress "1080::8:800:200C:417A"
552
+
553
+ All three are giving out the same IPv6 object. The default subnet mask
554
+ for an IPv6 is 128, as IPv6 addresses don't have classes like IPv4
555
+ addresses. If you want a different mask, you can go ahead and explicit
556
+ it:
557
+
558
+ ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
559
+
560
+ Access the address portion and the prefix by using the respective
561
+ methods:
562
+
563
+ ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
564
+
565
+ ip6.address
566
+ #=> "2001:0db8:0000:0000:0008:0800:200c:417a"
567
+
568
+ ip6.prefix
569
+ #=> 64
570
+
571
+ A compressed version of the IPv6 address can be obtained with the
572
+ IPv6#compressed method:
573
+
574
+ ip6 = IPAddress "2001:0db8:0000:0000:0008:200c:417a:00ab/64"
575
+
576
+ ip6.compressed
577
+ #=> "2001:db8::8:800:200c:417a"
578
+
579
+ == Handling the IPv6 address
580
+
581
+ Accessing the groups that form an IPv6 address is very easy with the
582
+ IPv6#groups method:
583
+
584
+ ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
585
+
586
+ ip6.groups
587
+ #=> [8193, 3512, 0, 0, 8, 2048, 8204, 16762]
588
+
589
+ As with IPv4 addresses, each individual group can be accessed using
590
+ the IPv6#[] shortcut method:
591
+
592
+ ip6[0]
593
+ #=> 8193
594
+ ip6[1]
595
+ #=> 3512
596
+ ip6[2]
597
+ #=> 0
598
+ ip6[3]
599
+ #=> 0
600
+
601
+ Note that each 16 bits group is expressed in its decimal form. You can
602
+ also obtain the groups into hexadecimal format using the IPv6#hexs
603
+ method:
604
+
605
+ ip6.hexs
606
+ #=> => ["2001", "0db8", "0000", "0000", "0008", "0800", "200c", "417a"]
607
+
608
+ A few other methods are available to transform an IPv6 address into
609
+ decimal representation, with IPv6.to_i
610
+
611
+ ip6.to_i
612
+ #=> 42540766411282592856906245548098208122
613
+
614
+ or to hexadecimal representation
615
+
616
+ ip6.to_hex
617
+ #=> "20010db80000000000080800200c417a"
618
+
619
+ To print out an IPv6 address in human readable form, use the IPv6#to_s
620
+ and IPv6#to_string methods
621
+
622
+ ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
623
+
624
+ ip6.to_s
625
+ #=> "2001:db8::8:800:200c:417a/96"
626
+
627
+ ip6.to_string
628
+ #=> "2001:0db8:0000:0000:0008:0800:200c:417a/96"
629
+
630
+ As you can see, IPv6.to_s prints out the compressed form, while
631
+ IPv6.to_string uses the expanded version.
632
+
633
+ === Compressing and uncompressing
634
+
635
+ If you have a string representing an IPv6 address, you can easily
636
+ compress it and uncompress it using the two class methods IPv6::expand
637
+ and IPv6::compress.
638
+
639
+ For example, let's say you have the following uncompressed IPv6
640
+ address:
641
+
642
+ ip6str = "2001:0DB8:0000:CD30:0000:0000:0000:0000"
643
+
644
+ Here is the compressed version:
645
+
646
+ IPAddress::IPv6.compress ip6str
647
+ #=> "2001:db8:0:cd30::"
648
+
649
+ The other way works as well:
650
+
651
+ ip6str = "2001:db8:0:cd30::"
652
+
653
+ IPAddress::IPv6.expand ip6str
654
+ #=> "2001:0DB8:0000:CD30:0000:0000:0000:0000"
655
+
656
+ These methods can be used when you don't want to create a new object
657
+ just for expanding or compressing an address (although a new object is
658
+ actually created internally).
659
+
660
+ == New IPv6 address from other formats
661
+
662
+ You can create a new IPv6 address from different formats than just a
663
+ string representing the colon-hex groups.
664
+
665
+ For instance, if you have a data stream, you can use IPv6::parse_data,
666
+ like in the following example:
667
+
668
+ data = " \001\r\270\000\000\000\000\000\b\b\000 \fAz"
669
+
670
+ ip6 = IPAddress::IPv6::parse_data data
671
+ ip6.prefix = 64
672
+
673
+ ip6.to_s
674
+ #=> "2001:db8::8:800:200c:417a/64"
675
+
676
+ A new IPv6 address can also be created from an unsigned 128 bits
677
+ integer:
678
+
679
+ u128 = 21932261930451111902915077091070067066
680
+
681
+ ip6 = IPAddress::IPv6::parse_u128 u128
682
+ ip6.prefix = 64
683
+
684
+ ip6.to_s
685
+ #=> "1080::8:800:200c:417a/64"
686
+
687
+ Finally, a new IPv6 address can be created from an hex string:
688
+
689
+ hex = "20010db80000000000080800200c417a"
690
+
691
+ ip6 = IPAddress::IPv6::parse_hex hex
692
+ ip6.prefix = 64
693
+
694
+ ip6.to_s
695
+ #=> "2001:db8::8:800:200c:417a/64"
696
+
697
+ == Special IPv6 addresses
698
+
699
+ Some IPv6 have a special meaning and are expressed in a special form,
700
+ quite different than an usual IPv6 address. IPAddress has builtin
701
+ support for unspecified, loopback and mapped IPv6 addresses.
702
+
703
+ === Unspecified address
704
+
705
+ The address with all zero bits is called the +unspecified+ address
706
+ (corresponding to 0.0.0.0 in IPv4). It should be something like this:
707
+
708
+ 0000:0000:0000:0000:0000:0000:0000:0000
709
+
710
+ but, with the use of compression, it is usually written as just two
711
+ colons:
712
+
713
+ ::
714
+
715
+ or, specifying the netmask:
716
+
717
+ ::/128
718
+
719
+ With IPAddress, create a new unspecified IPv6 address using its own
720
+ subclass:
721
+
722
+ ip = IPAddress::IPv6::Unspecified.new
723
+
724
+ ip.to_s
725
+ #=> => "::/128"
726
+
727
+ You can easily check if an IPv6 object is an unspecified address by
728
+ using the IPv6#unspecified? method
729
+
730
+ ip.unspecified?
731
+ #=> true
732
+
733
+ An unspecified IPv6 address can also be created with the wrapper
734
+ method, like we've seen before
735
+
736
+ ip = IPAddress "::"
737
+
738
+ ip.unspecified?
739
+ #=> true
740
+
741
+ This address must never be assigned to an interface and is to be used
742
+ only in software before the application has learned its host's source
743
+ address appropriate for a pending connection. Routers must not forward
744
+ packets with the unspecified address.
745
+
746
+ === Loopback address
747
+
748
+ The loopback address is a unicast localhost address. If an
749
+ application in a host sends packets to this address, the IPv6 stack
750
+ will loop these packets back on the same virtual interface.
751
+
752
+ Loopback addresses are expressed in the following form:
753
+
754
+ ::1
755
+
756
+ or, with their appropriate prefix,
757
+
758
+ ::1/128
759
+
760
+ As for the unspecified addresses, IPv6 loopbacks can be created with
761
+ IPAddress calling their own class:
762
+
763
+ ip = IPAddress::IPv6::Loopback.new
764
+
765
+ ip.to_s
766
+ #=> "::1/128"
767
+
768
+ or by using the wrapper:
769
+
770
+ ip = IPAddress "::1"
771
+
772
+ ip.to_s
773
+ #=> "::1/128"
774
+
775
+ Checking if an address is loopback is easy with the IPv6#loopback?
776
+ method:
777
+
778
+ ip.loopback?
779
+ #=> true
780
+
781
+ The IPv6 loopback address corresponds to 127.0.0.1 in IPv4.
782
+
783
+ === Mapped address
784
+
785
+ It is usually identified as a IPv4 mapped IPv6 address, a particular
786
+ IPv6 address which aids the transition from IPv4 to IPv6. The
787
+ structure of the address is
788
+
789
+ ::ffff:w.y.x.z
790
+
791
+ where w.x.y.z is a normal IPv4 address. For example, the following is
792
+ a mapped IPv6 address:
793
+
794
+ ::ffff:192.168.100.1
795
+
796
+ IPAddress is very powerful in handling mapped IPv6 addresses, as the
797
+ IPv4 portion is stored internally as a normal IPv4 object. Let's have
798
+ a look at some examples. To create a new mapped address, just use the
799
+ class builder itself
800
+
801
+ ip6 = IPAddress::IPv6::Mapped.new "::ffff:172.16.10.1/128"
802
+
803
+ or just use the wrapper method
804
+
805
+ ip6 = IPAddress "::ffff:172.16.10.1/128"
806
+
807
+ Let's check it's really a mapped address:
808
+
809
+ ip6.mapped?
810
+ #=> true
811
+
812
+ ip6.to_s
813
+ #=> "::FFFF:172.16.10.1/128"
814
+
815
+ Now with the +ipv4+ attribute, we can easily access the IPv4 portion
816
+ of the mapped IPv6 address:
817
+
818
+ ip6.ipv4.address
819
+ #=> "172.16.10.1"
820
+
821
+ Internally, the IPv4 address is stored as two 16 bits
822
+ groups. Therefore all the usual methods for an IPv6 address are
823
+ working perfectly fine:
824
+
825
+ ip6.to_hex
826
+ #=> "00000000000000000000ffffac100a01"
827
+
828
+ ip6.address
829
+ #=> "0000:0000:0000:0000:0000:ffff:ac10:0a01"
830
+
831
+ A mapped IPv6 can also be created just by specify the address in the
832
+ following format:
833
+
834
+ ip6 = IPAddress "::172.16.10.1"
835
+
836
+ That is, two colons and the IPv4 address. However, as by RFC, the ffff
837
+ group will be automatically added at the beginning
838
+
839
+ ip6.to_s
840
+ => "::ffff:172.16.10.1/128"
841
+
842
+ making it a mapped IPv6 compatible address.
843
+
844
+ = Future versions:
845
+
846
+ Some new features we'd like to add in the future versions:
847
+
848
+ * support for wildmasks
849
+ * network design methods for IPv6
850
+ * parameter to IPv4#subnet to select where to fill the space
851
+ (beginning or ending)
852
+ * method to check if a network is private
853
+
854
+ Stay tuned!
855
+
856
+ = Thanks to
857
+
858
+ Thanks to Luca Russo (vargolo) for all the support and technical
859
+ review.
860
+
861
+ = Copyright
862
+
863
+ Copyright (c) 2009-2010 Marco Ceresa. See LICENSE for details.
864
+
865
+
866
+