relevance_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,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
+