relevance_ipaddress 0.5.0

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