ipaddress_2 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1274 @@
1
+ require 'ipaddress_2/prefix'
2
+
3
+ module IPAddress;
4
+ #
5
+ # =Name
6
+ #
7
+ # IPAddress::IPv6 - IP version 6 address manipulation library
8
+ #
9
+ # =Synopsis
10
+ #
11
+ # require 'ipaddress'
12
+ #
13
+ # =Description
14
+ #
15
+ # Class IPAddress::IPv6 is used to handle IPv6 type addresses.
16
+ #
17
+ # == IPv6 addresses
18
+ #
19
+ # IPv6 addresses are 128 bits long, in contrast with IPv4 addresses
20
+ # which are only 32 bits long. An IPv6 address is generally written as
21
+ # eight groups of four hexadecimal digits, each group representing 16
22
+ # bits or two octect. For example, the following is a valid IPv6
23
+ # address:
24
+ #
25
+ # 2001:0db8:0000:0000:0008:0800:200c:417a
26
+ #
27
+ # Letters in an IPv6 address are usually written downcase, as per
28
+ # RFC. You can create a new IPv6 object using uppercase letters, but
29
+ # they will be converted.
30
+ #
31
+ # === Compression
32
+ #
33
+ # Since IPv6 addresses are very long to write, there are some
34
+ # semplifications and compressions that you can use to shorten them.
35
+ #
36
+ # * Leading zeroes: all the leading zeroes within a group can be
37
+ # omitted: "0008" would become "8"
38
+ #
39
+ # * A string of consecutive zeroes can be replaced by the string
40
+ # "::". This can be only applied once.
41
+ #
42
+ # Using compression, the IPv6 address written above can be shorten into
43
+ # the following, equivalent, address
44
+ #
45
+ # 2001:db8::8:800:200c:417a
46
+ #
47
+ # This short version is often used in human representation.
48
+ #
49
+ # === Network Mask
50
+ #
51
+ # As we used to do with IPv4 addresses, an IPv6 address can be written
52
+ # using the prefix notation to specify the subnet mask:
53
+ #
54
+ # 2001:db8::8:800:200c:417a/64
55
+ #
56
+ # The /64 part means that the first 64 bits of the address are
57
+ # representing the network portion, and the last 64 bits are the host
58
+ # portion.
59
+ #
60
+ #
61
+ class IPv6
62
+
63
+ include IPAddress
64
+ include Enumerable
65
+ include Comparable
66
+
67
+
68
+ #
69
+ # Format string to pretty print IPv6 addresses
70
+ #
71
+ IN6FORMAT = ("%.4x:"*8).chop
72
+
73
+ #
74
+ # Creates a new IPv6 address object.
75
+ #
76
+ # An IPv6 address can be expressed in any of the following forms:
77
+ #
78
+ # * "2001:0db8:0000:0000:0008:0800:200C:417A": IPv6 address with no compression
79
+ # * "2001:db8:0:0:8:800:200C:417A": IPv6 address with leading zeros compression
80
+ # * "2001:db8::8:800:200C:417A": IPv6 address with full compression
81
+ #
82
+ # In all these 3 cases, a new IPv6 address object will be created, using the default
83
+ # subnet mask /128
84
+ #
85
+ # You can also specify the subnet mask as with IPv4 addresses:
86
+ #
87
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
88
+ #
89
+ def initialize(str)
90
+ raise ArgumentError, "Nil IP" unless str
91
+ ip, netmask = str.split("/")
92
+
93
+ if str =~ /:.+\./
94
+ raise ArgumentError, "Please use #{self.class}::Mapped for IPv4 mapped addresses"
95
+ end
96
+
97
+ if IPAddress.valid_ipv6?(ip)
98
+ @groups = self.class.groups(ip)
99
+ @address = IN6FORMAT % @groups
100
+ @compressed = compress_address
101
+ else
102
+ raise ArgumentError, "Invalid IP #{ip.inspect}"
103
+ end
104
+
105
+ @prefix = Prefix128.new(netmask ? netmask : 128)
106
+ @allocator = 0
107
+
108
+ end # def initialize
109
+
110
+ #
111
+ # Returns the IPv6 address in uncompressed form:
112
+ #
113
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
114
+ #
115
+ # ip6.address
116
+ # #=> "2001:0db8:0000:0000:0008:0800:200c:417a"
117
+ #
118
+ def address
119
+ @address
120
+ end
121
+
122
+ # When serializing to JSON format, just use the string representation
123
+ #
124
+ # ip = IPAddress "2001:db8::8:800:200c:417a/64"
125
+ #
126
+ # ip.as_json
127
+ # #=> "2001:db8::8:800:200c:417a/64"
128
+ #
129
+ def as_json
130
+ to_string
131
+ end
132
+
133
+ #
134
+ # Returns an array with the 16 bits groups in decimal
135
+ # format:
136
+ #
137
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
138
+ #
139
+ # ip6.groups
140
+ # #=> [8193, 3512, 0, 0, 8, 2048, 8204, 16762]
141
+ #
142
+ def groups
143
+ @groups
144
+ end
145
+
146
+ #
147
+ # Returns an instance of the prefix object
148
+ #
149
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
150
+ #
151
+ # ip6.prefix
152
+ # #=> 64
153
+ #
154
+ def prefix
155
+ @prefix
156
+ end
157
+
158
+ #
159
+ # Set a new prefix number for the object
160
+ #
161
+ # This is useful if you want to change the prefix
162
+ # to an object created with IPv6::parse_u128 or
163
+ # if the object was created using the default prefix
164
+ # of 128 bits.
165
+ #
166
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a")
167
+ #
168
+ # puts ip6.to_string
169
+ # #=> "2001:db8::8:800:200c:417a/128"
170
+ #
171
+ # ip6.prefix = 64
172
+ # puts ip6.to_string
173
+ # #=> "2001:db8::8:800:200c:417a/64"
174
+ #
175
+ def prefix=(num)
176
+ @prefix = Prefix128.new(num)
177
+ end
178
+
179
+ #
180
+ # Unlike its counterpart IPv6#to_string method, IPv6#to_string_uncompressed
181
+ # returns the whole IPv6 address and prefix in an uncompressed form
182
+ #
183
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
184
+ #
185
+ # ip6.to_string_uncompressed
186
+ # #=> "2001:0db8:0000:0000:0008:0800:200c:417a/64"
187
+ #
188
+ def to_string_uncompressed
189
+ "#@address/#@prefix"
190
+ end
191
+
192
+ #
193
+ # Returns the IPv6 address in a human readable form,
194
+ # using the compressed address.
195
+ #
196
+ # ip6 = IPAddress "2001:0db8:0000:0000:0008:0800:200c:417a/64"
197
+ #
198
+ # ip6.to_string
199
+ # #=> "2001:db8::8:800:200c:417a/64"
200
+ #
201
+ def to_string
202
+ "#@compressed/#@prefix"
203
+ end
204
+
205
+ #
206
+ # Returns the IPv6 address in a human readable form,
207
+ # using the compressed address.
208
+ #
209
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
210
+ #
211
+ # ip6.to_s
212
+ # #=> "2001:db8::8:800:200c:417a"
213
+ #
214
+ def to_s
215
+ @compressed
216
+ end
217
+
218
+ #
219
+ # Returns a decimal format (unsigned 128 bit) of the
220
+ # IPv6 address
221
+ #
222
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
223
+ #
224
+ # ip6.to_i
225
+ # #=> 42540766411282592856906245548098208122
226
+ #
227
+ def to_i
228
+ to_hex.hex
229
+ end
230
+ alias_method :to_u128, :to_i
231
+
232
+ #
233
+ # True if the IPv6 address is a network
234
+ #
235
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
236
+ #
237
+ # ip6.network?
238
+ # #=> false
239
+ #
240
+ # ip6 = IPAddress "2001:db8:8:800::/64"
241
+ #
242
+ # ip6.network?
243
+ # #=> true
244
+ #
245
+ def network?
246
+ to_u128 | @prefix.to_u128 == @prefix.to_u128
247
+ end
248
+
249
+ #
250
+ # Returns the 16-bits value specified by index
251
+ #
252
+ # ip = IPAddress("2001:db8::8:800:200c:417a/64")
253
+ #
254
+ # ip[0]
255
+ # #=> 8193
256
+ # ip[1]
257
+ # #=> 3512
258
+ # ip[2]
259
+ # #=> 0
260
+ # ip[3]
261
+ # #=> 0
262
+ #
263
+ def [](index)
264
+ @groups[index]
265
+ end
266
+ alias_method :group, :[]
267
+
268
+ #
269
+ # Updated the octet specified at index
270
+ #
271
+ def []=(index, value)
272
+ @groups[index] = value
273
+ initialize("#{IN6FORMAT % @groups}/#{prefix}")
274
+ end
275
+ alias_method :group=, :[]=
276
+
277
+ #
278
+ # Returns a Base16 number representing the IPv6
279
+ # address
280
+ #
281
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
282
+ #
283
+ # ip6.to_hex
284
+ # #=> "20010db80000000000080800200c417a"
285
+ #
286
+ def to_hex
287
+ hexs.join("")
288
+ end
289
+
290
+ # Returns the address portion of an IPv6 object
291
+ # in a network byte order format.
292
+ #
293
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
294
+ #
295
+ # ip6.data
296
+ # #=> " \001\r\270\000\000\000\000\000\b\b\000 \fAz"
297
+ #
298
+ # It is usually used to include an IP address
299
+ # in a data packet to be sent over a socket
300
+ #
301
+ # a = Socket.open(params) # socket details here
302
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
303
+ # binary_data = ["Address: "].pack("a*") + ip.data
304
+ #
305
+ # # Send binary data
306
+ # a.puts binary_data
307
+ #
308
+ def data
309
+ @groups.pack("n8")
310
+ end
311
+
312
+ #
313
+ # Returns an array of the 16 bits groups in hexdecimal
314
+ # format:
315
+ #
316
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
317
+ #
318
+ # ip6.hexs
319
+ # #=> ["2001", "0db8", "0000", "0000", "0008", "0800", "200c", "417a"]
320
+ #
321
+ # Not to be confused with the similar IPv6#to_hex method.
322
+ #
323
+ def hexs
324
+ @address.split(":")
325
+ end
326
+
327
+ #
328
+ # Returns the IPv6 address in a DNS reverse lookup
329
+ # string, as per RFC3172 and RFC2874.
330
+ #
331
+ # ip6 = IPAddress "3ffe:505:2::f"
332
+ #
333
+ # ip6.reverse
334
+ # #=> "f.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.5.0.5.0.e.f.f.3.ip6.arpa"
335
+ #
336
+ def reverse
337
+ to_hex.reverse.gsub(/./){|c| c+"."} + "ip6.arpa"
338
+ end
339
+ alias_method :arpa, :reverse
340
+
341
+ #
342
+ # Splits a network into different subnets
343
+ #
344
+ # NOTE: Will allow you to split past /64 against RFC 5375
345
+ #
346
+ # If the IP Address is a network, it can be divided into
347
+ # multiple networks. If +self+ is not a network, this
348
+ # method will calculate the network from the IP and then
349
+ # subnet it.
350
+ #
351
+ # If +subnets+ is an power of two number, the resulting
352
+ # networks will be divided evenly from the supernet.
353
+ #
354
+ # network = IPAddress("2001:db8:8::/48")
355
+ #
356
+ # network / 4 # implies map{|i| i.to_string}
357
+ # #=> ["2001:db8:8::/50",
358
+ # #=> "2001:db8:8:4000::/50",
359
+ # #=> "2001:db8:8:8000::/50",
360
+ # #=> "2001:db8:8:c000::/50"]
361
+ #
362
+ # If +num+ is any other number, the supernet will be
363
+ # divided into some networks with a even number of hosts and
364
+ # other networks with the remaining addresses.
365
+ #
366
+ # network = IPAddress("2001:db8:8::/48")
367
+ #
368
+ # network / 3 # implies map{|i| i.to_string}
369
+ #
370
+ # #=> ["2001:db8:8::/50",
371
+ # #=> "2001:db8:8:4000::/50",
372
+ # #=> "2001:db8:8:8000::/49"]
373
+ #
374
+ # Returns an array of IPv6 objects
375
+ #
376
+ def split(subnets=2)
377
+ unless (1..(2**@prefix.host_prefix)).include? subnets
378
+ raise ArgumentError, "Value #{subnets} out of range"
379
+ end
380
+ networks = subnet(newprefix(subnets))
381
+ until networks.size == subnets
382
+ networks = sum_first_found(networks)
383
+ end
384
+ return networks
385
+ end
386
+ alias_method :/, :split
387
+
388
+ #
389
+ # Returns the network number in Unsigned 128bits format
390
+ #
391
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
392
+ #
393
+ # ip6.network_u128
394
+ # #=> 42540766411282592856903984951653826560
395
+ #
396
+ def network_u128
397
+ to_u128 & @prefix.to_u128
398
+ end
399
+
400
+ #
401
+ # Returns the broadcast address in Unsigned 128bits format
402
+ #
403
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
404
+ #
405
+ # ip6.broadcast_u128
406
+ # #=> 42540766411282592875350729025363378175
407
+ #
408
+ # Please note that there is no Broadcast concept in IPv6
409
+ # addresses as in IPv4 addresses, and this method is just
410
+ # an helper to other functions.
411
+ #
412
+ def broadcast_u128
413
+ network_u128 + size - 1
414
+ end
415
+
416
+ #
417
+ # Returns the number of IP addresses included
418
+ # in the network. It also counts the network
419
+ # address and the broadcast address.
420
+ #
421
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a/64")
422
+ #
423
+ # ip6.size
424
+ # #=> 18446744073709551616
425
+ #
426
+ def size
427
+ 2 ** @prefix.host_prefix
428
+ end
429
+
430
+ #
431
+ # Checks whether a subnet includes the given IP address.
432
+ #
433
+ # Example:
434
+ #
435
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
436
+ # addr = IPAddress "2001:db8::8:800:200c:1/128"
437
+ #
438
+ # ip6.include? addr
439
+ # #=> true
440
+ #
441
+ # ip6.include? IPAddress("2001:db8:1::8:800:200c:417a/76")
442
+ # #=> false
443
+ #
444
+ def include?(oth)
445
+ @prefix <= oth.prefix and network_u128 == self.class.new(oth.address+"/#@prefix").network_u128
446
+ end
447
+
448
+ #
449
+ # Checks whether a subnet includes all the
450
+ # given IPv4 objects.
451
+ #
452
+ # ip = IPAddress("2001:db8:8:800::1/64")
453
+ #
454
+ # addr1 = IPAddress("2001:db8:8:800::2/64")
455
+ # addr2 = IPAddress("2001:db8:8:800::8/64")
456
+ #
457
+ # ip.include_all?(addr1,addr2)
458
+ # #=> true
459
+ #
460
+ def include_all?(*others)
461
+ others.all? {|oth| include?(oth)}
462
+ end
463
+
464
+ #
465
+ # Compressed form of the IPv6 address
466
+ #
467
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
468
+ #
469
+ # ip6.compressed
470
+ # #=> "2001:db8::8:800:200c:417a"
471
+ #
472
+ def compressed
473
+ @compressed
474
+ end
475
+
476
+ #
477
+ # Returns true if the address is an unspecified address
478
+ #
479
+ # See IPAddress::IPv6::Unspecified for more information
480
+ #
481
+ def unspecified?
482
+ @prefix == 128 and @compressed == "::"
483
+ end
484
+
485
+ #
486
+ # Returns true if the address is a loopback address
487
+ #
488
+ # See IPAddress::IPv6::Loopback for more information
489
+ #
490
+ def loopback?
491
+ @prefix == 128 and @compressed == "::1"
492
+ end
493
+
494
+ #
495
+ # Checks if an IPv6 address objects belongs
496
+ # to a link-local network RFC4291
497
+ #
498
+ # Example:
499
+ #
500
+ # ip = IPAddress "fe80::1"
501
+ # ip.link_local?
502
+ # #=> true
503
+ #
504
+ def link_local?
505
+ [self.class.new("fe80::/10")].any? {|i| i.include? self}
506
+ end
507
+
508
+ #
509
+ # Checks if an IPv6 address objects belongs
510
+ # to a unique-local network RFC4193
511
+ #
512
+ # Example:
513
+ #
514
+ # ip = IPAddress "fc00::1"
515
+ # ip.unique_local?
516
+ # #=> true
517
+ #
518
+ def unique_local?
519
+ [self.class.new("fc00::/7")].any? {|i| i.include? self}
520
+ end
521
+
522
+ #
523
+ # Returns true if the address is a mapped address
524
+ #
525
+ # See IPAddress::IPv6::Mapped for more information
526
+ #
527
+ def mapped?
528
+ to_u128 >> 32 == 0xffff
529
+ end
530
+
531
+ #
532
+ # Returns a new IPv6 object which is the result
533
+ # of the summarization, if possible, of the two
534
+ # objects
535
+ #
536
+ # Example:
537
+ #
538
+ # ip1 = IPAddress("172.16.10.1/24")
539
+ # ip2 = IPAddress("172.16.11.2/24")
540
+ #
541
+ # p (ip1 + ip2).map {|i| i.to_string}
542
+ # #=> ["172.16.10.0/23"]
543
+ #
544
+ # If the networks are not contiguous, returns
545
+ # the two network numbers from the objects
546
+ #
547
+ # ip1 = IPAddress("10.0.0.1/24")
548
+ # ip2 = IPAddress("10.0.2.1/24")
549
+ #
550
+ # p (ip1 + ip2).map {|i| i.to_string}
551
+ # #=> ["10.0.0.0/24","10.0.2.0/24"]
552
+ #
553
+ def +(oth)
554
+ aggregate(*[self,oth].sort.map{|i| i.network})
555
+ end
556
+
557
+ #
558
+ # Returns a new IPv4 object from the supernetting
559
+ # of the instance network.
560
+ #
561
+ # Supernetting is similar to subnetting, except
562
+ # that you getting as a result a network with a
563
+ # smaller prefix (bigger host space). For example,
564
+ # given the network
565
+ #
566
+ # ip = IPAddress("2001:db8:8:800::1/64")
567
+ #
568
+ # you can supernet it with a new /32 prefix
569
+ #
570
+ # ip.supernet(32).to_string
571
+ # #=> "2001:db8::/32"
572
+ #
573
+ # However if you supernet it with a /22 prefix, the
574
+ # network address will change:
575
+ #
576
+ # ip.supernet(22).to_string
577
+ # #=> "2001:c00::/22"
578
+ #
579
+ # If +new_prefix+ is less than 1, returns 0000:0000:0000:0000:0000:0000:0000:0000/0
580
+ #
581
+ def supernet(new_prefix)
582
+ raise ArgumentError, "New prefix must be smaller than existing prefix" if new_prefix >= @prefix.to_i
583
+ return self.class.new("0000:0000:0000:0000:0000:0000:0000:0000/0") if new_prefix < 1
584
+ return self.class.new(@address+"/#{new_prefix}").network
585
+ end
586
+
587
+ #
588
+ # This method implements the subnetting function
589
+ # similar to the one described in RFC3531.
590
+ #
591
+ # By specifying a new prefix, the method calculates
592
+ # the network number for the given IPv4 object
593
+ # and calculates the subnets associated to the new
594
+ # prefix.
595
+ #
596
+ # For example, given the following network:
597
+ #
598
+ # ip = IPAddress "172.16.10.0/24"
599
+ #
600
+ # we can calculate the subnets with a /26 prefix
601
+ #
602
+ # ip.subnet(26).map{&:to_string)
603
+ # #=> ["172.16.10.0/26", "172.16.10.64/26",
604
+ # "172.16.10.128/26", "172.16.10.192/26"]
605
+ #
606
+ # The resulting number of subnets will of course always be
607
+ # a power of two.
608
+ #
609
+ def subnet(subprefix)
610
+ unless ((@prefix.to_i)..128).include? subprefix
611
+ raise ArgumentError, "New prefix must be between #@prefix and 128"
612
+ end
613
+ Array.new(2**(subprefix-@prefix.to_i)) do |i|
614
+ self.class.parse_u128(network_u128+(i*(2**(128-subprefix))), subprefix)
615
+ end
616
+ end
617
+
618
+
619
+ #
620
+ # Iterates over all the IP addresses for the given
621
+ # network (or IP address).
622
+ #
623
+ # The object yielded is a new IPv6 object created
624
+ # from the iteration.
625
+ #
626
+ # ip6 = IPAddress("2001:db8::4/125")
627
+ #
628
+ # ip6.each do |i|
629
+ # p i.compressed
630
+ # end
631
+ # #=> "2001:db8::"
632
+ # #=> "2001:db8::1"
633
+ # #=> "2001:db8::2"
634
+ # #=> "2001:db8::3"
635
+ # #=> "2001:db8::4"
636
+ # #=> "2001:db8::5"
637
+ # #=> "2001:db8::6"
638
+ # #=> "2001:db8::7"
639
+ #
640
+ # WARNING: if the host portion is very large, this method
641
+ # can be very slow and possibly hang your system!
642
+ #
643
+ def each
644
+ (network_u128..broadcast_u128).each do |i|
645
+ yield self.class.parse_u128(i, @prefix)
646
+ end
647
+ end
648
+
649
+ #
650
+ # Returns the successor to the IP address
651
+ #
652
+ # Example:
653
+ #
654
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a/64")
655
+ #
656
+ # ip6.succ.to_string
657
+ # => "2001:db8::8:800:200c:417b/64"
658
+ #
659
+ def succ
660
+ IPAddress::IPv6.parse_u128(to_u128.succ, prefix)
661
+ end
662
+ alias_method :next, :succ
663
+
664
+ #
665
+ # Returns the predecessor to the IP address
666
+ #
667
+ # Example:
668
+ #
669
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a/64")
670
+ #
671
+ # ip6.pred.to_string
672
+ # => "2001:db8::8:800:200c:4179/64"
673
+ #
674
+ def pred
675
+ IPAddress::IPv6.parse_u128(to_u128.pred, prefix)
676
+ end
677
+
678
+ #
679
+ # Spaceship operator to compare IPv6 objects
680
+ #
681
+ # Comparing IPv6 addresses is useful to ordinate
682
+ # them into lists that match our intuitive
683
+ # perception of ordered IP addresses.
684
+ #
685
+ # The first comparison criteria is the u128 value.
686
+ # For example, 2001:db8:1::1 will be considered
687
+ # to be less than 2001:db8:2::1, because, in a ordered list,
688
+ # we expect 2001:db8:1::1 to come before 2001:db8:2::1.
689
+ #
690
+ # The second criteria, in case two IPv6 objects
691
+ # have identical addresses, is the prefix. An higher
692
+ # prefix will be considered greater than a lower
693
+ # prefix. This is because we expect to see
694
+ # 2001:db8:1::1/64 come before 2001:db8:1::1/65
695
+ #
696
+ # Example:
697
+ #
698
+ # ip1 = IPAddress "2001:db8:1::1/64"
699
+ # ip2 = IPAddress "2001:db8:2::1/64"
700
+ # ip3 = IPAddress "2001:db8:1::1/65"
701
+ #
702
+ # ip1 < ip2
703
+ # #=> true
704
+ # ip1 < ip3
705
+ # #=> false
706
+ #
707
+ # [ip1,ip2,ip3].sort.map{|i| i.to_string}
708
+ # #=> ["2001:db8:1::1/64","2001:db8:1::1/65","2001:db8:2::1/64"]
709
+ #
710
+ def <=>(oth)
711
+ return nil unless oth.is_a?(self.class)
712
+ return prefix <=> oth.prefix if to_u128 == oth.to_u128
713
+ to_u128 <=> oth.to_u128
714
+ end
715
+
716
+ #
717
+ # Returns the address portion of an IP in binary format,
718
+ # as a string containing a sequence of 0 and 1
719
+ #
720
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a")
721
+ #
722
+ # ip6.bits
723
+ # #=> "0010000000000001000011011011100000 [...] "
724
+ #
725
+ def bits
726
+ data.unpack("B*").first
727
+ end
728
+
729
+ #
730
+ # Expands an IPv6 address in the canocical form
731
+ #
732
+ # IPAddress::IPv6.expand "2001:0DB8:0:CD30::"
733
+ # #=> "2001:0DB8:0000:CD30:0000:0000:0000:0000"
734
+ #
735
+ def self.expand(str)
736
+ self.new(str).address
737
+ end
738
+
739
+ #
740
+ # Compress an IPv6 address in its compressed form
741
+ #
742
+ # IPAddress::IPv6.compress "2001:0DB8:0000:CD30:0000:0000:0000:0000"
743
+ # #=> "2001:db8:0:cd30::"
744
+ #
745
+ def self.compress(str)
746
+ self.new(str).compressed
747
+ end
748
+
749
+ #
750
+ # Literal version of the IPv6 address
751
+ #
752
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
753
+ #
754
+ # ip6.literal
755
+ # #=> "2001-0db8-0000-0000-0008-0800-200c-417a.ipv6-literal.net"
756
+ #
757
+ def literal
758
+ @address.gsub(":","-") + ".ipv6-literal.net"
759
+ end
760
+
761
+ #
762
+ # Returns a new IPv6 object with the network number
763
+ # for the given IP.
764
+ #
765
+ # ip = IPAddress "2001:db8:1:1:1:1:1:1/32"
766
+ #
767
+ # ip.network.to_string
768
+ # #=> "2001:db8::/32"
769
+ #
770
+ def network
771
+ self.class.parse_u128(network_u128, @prefix)
772
+ end
773
+
774
+ #
775
+ # Extract 16 bits groups from a string
776
+ #
777
+ def self.groups(str)
778
+ l, r = if str =~ /^(.*)::(.*)$/
779
+ [$1,$2].map {|i| i.split ":"}
780
+ else
781
+ [str.split(":"),[]]
782
+ end
783
+ (l + Array.new(8-l.size-r.size, '0') + r).map {|i| i.hex}
784
+ end
785
+
786
+ #
787
+ # Creates a new IPv6 object from binary data,
788
+ # like the one you get from a network stream.
789
+ #
790
+ # For example, on a network stream the IP
791
+ #
792
+ # "2001:db8::8:800:200c:417a"
793
+ #
794
+ # is represented with the binary data
795
+ #
796
+ # " \001\r\270\000\000\000\000\000\b\b\000 \fAz"
797
+ #
798
+ # With that data you can create a new IPv6 object:
799
+ #
800
+ # ip6 = IPAddress::IPv6::parse_data " \001\r\270\000\000\000\000\000\b\b\000 \fAz"
801
+ # ip6.prefix = 64
802
+ #
803
+ # ip6.to_s
804
+ # #=> "2001:db8::8:800:200c:417a/64"
805
+ #
806
+ def self.parse_data(str)
807
+ self.new(IN6FORMAT % str.unpack("n8"))
808
+ end
809
+
810
+ #
811
+ # Creates a new IPv6 object from an
812
+ # unsigned 128 bits integer.
813
+ #
814
+ # ip6 = IPAddress::IPv6::parse_u128(42540766411282592856906245548098208122)
815
+ # ip6.prefix = 64
816
+ #
817
+ # ip6.to_string
818
+ # #=> "2001:db8::8:800:200c:417a/64"
819
+ #
820
+ # The +prefix+ parameter is optional:
821
+ #
822
+ # ip6 = IPAddress::IPv6::parse_u128(42540766411282592856906245548098208122, 64)
823
+ #
824
+ # ip6.to_string
825
+ # #=> "2001:db8::8:800:200c:417a/64"
826
+ #
827
+ def self.parse_u128(u128, prefix=128)
828
+ str = IN6FORMAT % (0..7).map{|i| (u128>>(112-16*i))&0xffff}
829
+ self.new(str + "/#{prefix}")
830
+ end
831
+
832
+ #
833
+ # Creates a new IPv6 object from a number expressed in
834
+ # hexdecimal format:
835
+ #
836
+ # ip6 = IPAddress::IPv6::parse_hex("20010db80000000000080800200c417a")
837
+ # ip6.prefix = 64
838
+ #
839
+ # ip6.to_string
840
+ # #=> "2001:db8::8:800:200c:417a/64"
841
+ #
842
+ # The +prefix+ parameter is optional:
843
+ #
844
+ # ip6 = IPAddress::IPv6::parse_hex("20010db80000000000080800200c417a", 64)
845
+ #
846
+ # ip6.to_string
847
+ # #=> "2001:db8::8:800:200c:417a/64"
848
+ #
849
+ def self.parse_hex(hex, prefix=128)
850
+ self.parse_u128(hex.hex, prefix)
851
+ end
852
+
853
+ #
854
+ # Summarization (or aggregation) is the process when two or more
855
+ # networks are taken together to check if a supernet, including all
856
+ # and only these networks, exists. If it exists then this supernet
857
+ # is called the summarized (or aggregated) network.
858
+ #
859
+ # It is very important to understand that summarization can only
860
+ # occur if there are no holes in the aggregated network, or, in other
861
+ # words, if the given networks fill completely the address space
862
+ # of the supernet. So the two rules are:
863
+ #
864
+ # 1) The aggregate network must contain +all+ the IP addresses of the
865
+ # original networks;
866
+ # 2) The aggregate network must contain +only+ the IP addresses of the
867
+ # original networks;
868
+ #
869
+ # A few examples will help clarify the above. Let's consider for
870
+ # instance the following two networks:
871
+ #
872
+ # ip1 = IPAddress("2001:db8:8:800::1/64")
873
+ # ip2 = IPAddress("2001:0db8:8:801::2/64")
874
+ #
875
+ # These two networks can be expressed using only one IP address
876
+ # network if we change the prefix. Let Ruby do the work:
877
+ #
878
+ # IPAddress::IPv6::summarize(ip1,ip2).to_s
879
+ # #=> "2001:db8:8:800::/63"
880
+ #
881
+ # We note how the network "2001:db8:8:800::/63" includes all the addresses
882
+ # specified in the above networks, and (more important) includes
883
+ # ONLY those addresses.
884
+ #
885
+ # If we summarized +ip1+ and +ip2+ with the following network:
886
+ #
887
+ # "2001:db8::/32"
888
+ #
889
+ # we would have satisfied rule #1 above, but not rule #2. So "2001:db8::/32"
890
+ # is not an aggregate network for +ip1+ and +ip2+.
891
+ #
892
+ # If it's not possible to compute a single aggregated network for all the
893
+ # original networks, the method returns an array with all the aggregate
894
+ # networks found. For example, the following four networks can be
895
+ # aggregated in a single /22:
896
+ #
897
+ # ip1 = IPAddress("2001:db8:8:800::1/64")
898
+ # ip2 = IPAddress("2001:db8:8:801::1/64")
899
+ # ip3 = IPAddress("2001:db8:8:802::1/64")
900
+ # ip4 = IPAddress("2001:db8:8:803::1/64")
901
+ #
902
+ # IPAddress::IPv6::summarize(ip1,ip2,ip3,ip4).to_string
903
+ # #=> "2001:db8:8:800::/62",
904
+ #
905
+ # But the following networks can't be summarized in a single network:
906
+ #
907
+ # ip1 = IPAddress("2001:db8:8:801::1/64")
908
+ # ip2 = IPAddress("2001:db8:8:802::1/64")
909
+ # ip3 = IPAddress("2001:db8:8:803::1/64")
910
+ # ip4 = IPAddress("2001:db8:8:804::1/64")
911
+ #
912
+ # IPAddress::IPv6::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
913
+ # #=> ["2001:db8:8:801::/64","2001:db8:8:802::/63","2001:db8:8:804::/64"]
914
+ #
915
+ def self.summarize(*args)
916
+ # one network? no need to summarize
917
+ return [args.first.network] if args.size == 1
918
+
919
+ i = 0
920
+ result = args.dup.sort.map{|ip| ip.network}
921
+ while i < result.size-1
922
+ sum = result[i] + result[i+1]
923
+ result[i..i+1] = sum.first if sum.size == 1
924
+ i += 1
925
+ end
926
+
927
+ result.flatten!
928
+ if result.size == args.size
929
+ # nothing more to summarize
930
+ return result
931
+ else
932
+ # keep on summarizing
933
+ return self.summarize(*result)
934
+ end
935
+ end
936
+
937
+ #
938
+ # Allocates a new ip from the current subnet. Optional skip parameter
939
+ # can be used to skip addresses.
940
+ #
941
+ # Will raise StopIteration exception when all addresses have been allocated
942
+ #
943
+ # Example:
944
+ #
945
+ # ip = IPAddress("10.0.0.0/24")
946
+ # ip.allocate
947
+ # #=> "10.0.0.1/24"
948
+ # ip.allocate
949
+ # #=> "10.0.0.2/24"
950
+ # ip.allocate(2)
951
+ # #=> "10.0.0.5/24"
952
+ #
953
+ #
954
+ # Uses an internal @allocator which tracks the state of allocated
955
+ # addresses.
956
+ #
957
+ def allocate(skip=0)
958
+ @allocator += 1 + skip
959
+
960
+ next_ip = network_u128+@allocator
961
+ if next_ip > broadcast_u128
962
+ raise StopIteration
963
+ end
964
+ self.class.parse_u128(next_ip, @prefix)
965
+ end
966
+
967
+ #
968
+ # Finds the adjacent block to a subnet.
969
+ #
970
+ # Example:
971
+ #
972
+ # ip = IPAddress("2001:db8::/32")
973
+ # ip.find_adjacent_subnet
974
+ # #=> "2001:db9::/32"
975
+ #
976
+ def find_adjacent_subnet
977
+ return false if prefix == 0
978
+ current_subnet = to_string
979
+ self.prefix = @prefix - 1
980
+ (split.map{|i| i.to_string} - [current_subnet])[0]
981
+ end
982
+
983
+ private
984
+
985
+ def newprefix(num)
986
+ return @prefix + (Math::log2(num).ceil )
987
+ end
988
+
989
+ def sum_first_found(arr)
990
+ dup = arr.dup.reverse
991
+ dup.each_with_index do |obj,i|
992
+ a = [self.class.summarize(obj,dup[i+1])].flatten
993
+ if a.size == 1
994
+ dup[i..i+1] = a
995
+ return dup.reverse
996
+ end
997
+ end
998
+ return dup.reverse
999
+ end
1000
+
1001
+ def compress_address
1002
+ str = @groups.map{|i| i.to_s 16}.join ":"
1003
+ loop do
1004
+ break if str.sub!(/\A0:0:0:0:0:0:0:0\Z/, '::')
1005
+ break if str.sub!(/\b0:0:0:0:0:0:0\b/, ':')
1006
+ break if str.sub!(/\b0:0:0:0:0:0\b/, ':')
1007
+ break if str.sub!(/\b0:0:0:0:0\b/, ':')
1008
+ break if str.sub!(/\b0:0:0:0\b/, ':')
1009
+ break if str.sub!(/\b0:0:0\b/, ':')
1010
+ break if str.sub!(/\b0:0\b/, ':')
1011
+ break
1012
+ end
1013
+ str.sub(/:{3,}/, '::')
1014
+ end
1015
+
1016
+ def aggregate(ip1,ip2)
1017
+ return [ip1] if ip1.include? ip2
1018
+
1019
+ snet = ip1.supernet(ip1.prefix-1)
1020
+ if snet.include_all?(ip1, ip2) && ((ip1.size + ip2.size) == snet.size)
1021
+ return [snet]
1022
+ else
1023
+ return [ip1, ip2]
1024
+ end
1025
+ end
1026
+
1027
+ end # class IPv6
1028
+
1029
+ #
1030
+ # The address with all zero bits is called the +unspecified+ address
1031
+ # (corresponding to 0.0.0.0 in IPv4). It should be something like this:
1032
+ #
1033
+ # 0000:0000:0000:0000:0000:0000:0000:0000
1034
+ #
1035
+ # but, with the use of compression, it is usually written as just two
1036
+ # colons:
1037
+ #
1038
+ # ::
1039
+ #
1040
+ # or, specifying the netmask:
1041
+ #
1042
+ # ::/128
1043
+ #
1044
+ # With IPAddress, create a new unspecified IPv6 address using its own
1045
+ # subclass:
1046
+ #
1047
+ # ip = IPAddress::IPv6::Unspecified.new
1048
+ #
1049
+ # ip.to_s
1050
+ # #=> => "::/128"
1051
+ #
1052
+ # You can easily check if an IPv6 object is an unspecified address by
1053
+ # using the IPv6#unspecified? method
1054
+ #
1055
+ # ip.unspecified?
1056
+ # #=> true
1057
+ #
1058
+ # An unspecified IPv6 address can also be created with the wrapper
1059
+ # method, like we've seen before
1060
+ #
1061
+ # ip = IPAddress "::"
1062
+ #
1063
+ # ip.unspecified?
1064
+ # #=> true
1065
+ #
1066
+ # This address must never be assigned to an interface and is to be used
1067
+ # only in software before the application has learned its host's source
1068
+ # address appropriate for a pending connection. Routers must not forward
1069
+ # packets with the unspecified address.
1070
+ #
1071
+ class IPAddress::IPv6::Unspecified < IPAddress::IPv6
1072
+ #
1073
+ # Creates a new IPv6 unspecified address
1074
+ #
1075
+ # ip = IPAddress::IPv6::Unspecified.new
1076
+ #
1077
+ # ip.to_s
1078
+ # #=> => "::/128"
1079
+ #
1080
+ def initialize
1081
+ @address = ("0000:"*8).chop
1082
+ @groups = Array.new(8,0)
1083
+ @prefix = Prefix128.new(128)
1084
+ @compressed = compress_address
1085
+ end
1086
+ end # class IPv6::Unspecified
1087
+
1088
+ #
1089
+ # The loopback address is a unicast localhost address. If an
1090
+ # application in a host sends packets to this address, the IPv6 stack
1091
+ # will loop these packets back on the same virtual interface.
1092
+ #
1093
+ # Loopback addresses are expressed in the following form:
1094
+ #
1095
+ # ::1
1096
+ #
1097
+ # or, with their appropriate prefix,
1098
+ #
1099
+ # ::1/128
1100
+ #
1101
+ # As for the unspecified addresses, IPv6 loopbacks can be created with
1102
+ # IPAddress calling their own class:
1103
+ #
1104
+ # ip = IPAddress::IPv6::Loopback.new
1105
+ #
1106
+ # ip.to_string
1107
+ # #=> "::1/128"
1108
+ #
1109
+ # or by using the wrapper:
1110
+ #
1111
+ # ip = IPAddress "::1"
1112
+ #
1113
+ # ip.to_string
1114
+ # #=> "::1/128"
1115
+ #
1116
+ # Checking if an address is loopback is easy with the IPv6#loopback?
1117
+ # method:
1118
+ #
1119
+ # ip.loopback?
1120
+ # #=> true
1121
+ #
1122
+ # The IPv6 loopback address corresponds to 127.0.0.1 in IPv4.
1123
+ #
1124
+ class IPAddress::IPv6::Loopback < IPAddress::IPv6
1125
+ #
1126
+ # Creates a new IPv6 unspecified address
1127
+ #
1128
+ # ip = IPAddress::IPv6::Loopback.new
1129
+ #
1130
+ # ip.to_string
1131
+ # #=> "::1/128"
1132
+ #
1133
+ def initialize
1134
+ @address = ("0000:"*7)+"0001"
1135
+ @groups = Array.new(7,0).push(1)
1136
+ @prefix = Prefix128.new(128)
1137
+ @compressed = compress_address
1138
+ end
1139
+ end # class IPv6::Loopback
1140
+
1141
+ #
1142
+ # It is usually identified as a IPv4 mapped IPv6 address, a particular
1143
+ # IPv6 address which aids the transition from IPv4 to IPv6. The
1144
+ # structure of the address is
1145
+ #
1146
+ # ::ffff:w.y.x.z
1147
+ #
1148
+ # where w.x.y.z is a normal IPv4 address. For example, the following is
1149
+ # a mapped IPv6 address:
1150
+ #
1151
+ # ::ffff:192.168.100.1
1152
+ #
1153
+ # IPAddress is very powerful in handling mapped IPv6 addresses, as the
1154
+ # IPv4 portion is stored internally as a normal IPv4 object. Let's have
1155
+ # a look at some examples. To create a new mapped address, just use the
1156
+ # class builder itself
1157
+ #
1158
+ # ip6 = IPAddress::IPv6::Mapped.new "::ffff:172.16.10.1/128"
1159
+ #
1160
+ # or just use the wrapper method
1161
+ #
1162
+ # ip6 = IPAddress "::ffff:172.16.10.1/128"
1163
+ #
1164
+ # Let's check it's really a mapped address:
1165
+ #
1166
+ # ip6.mapped?
1167
+ # #=> true
1168
+ #
1169
+ # ip6.to_string
1170
+ # #=> "::FFFF:172.16.10.1/128"
1171
+ #
1172
+ # Now with the +ipv4+ attribute, we can easily access the IPv4 portion
1173
+ # of the mapped IPv6 address:
1174
+ #
1175
+ # ip6.ipv4.address
1176
+ # #=> "172.16.10.1"
1177
+ #
1178
+ # Internally, the IPv4 address is stored as two 16 bits
1179
+ # groups. Therefore all the usual methods for an IPv6 address are
1180
+ # working perfectly fine:
1181
+ #
1182
+ # ip6.to_hex
1183
+ # #=> "00000000000000000000ffffac100a01"
1184
+ #
1185
+ # ip6.address
1186
+ # #=> "0000:0000:0000:0000:0000:ffff:ac10:0a01"
1187
+ #
1188
+ # A mapped IPv6 can also be created just by specify the address in the
1189
+ # following format:
1190
+ #
1191
+ # ip6 = IPAddress "::172.16.10.1"
1192
+ #
1193
+ # That is, two colons and the IPv4 address. However, as by RFC, the ffff
1194
+ # group will be automatically added at the beginning
1195
+ #
1196
+ # ip6.to_string
1197
+ # => "::ffff:172.16.10.1/128"
1198
+ #
1199
+ # making it a mapped IPv6 compatible address.
1200
+ #
1201
+ class IPAddress::IPv6::Mapped < IPAddress::IPv6
1202
+
1203
+ # Access the internal IPv4 address
1204
+ attr_reader :ipv4
1205
+
1206
+ #
1207
+ # Creates a new IPv6 IPv4-mapped address
1208
+ #
1209
+ # ip6 = IPAddress::IPv6::Mapped.new "::ffff:172.16.10.1/128"
1210
+ #
1211
+ # ipv6.ipv4.class
1212
+ # #=> IPAddress::IPv4
1213
+ #
1214
+ # An IPv6 IPv4-mapped address can also be created using the
1215
+ # IPv6 only format of the address:
1216
+ #
1217
+ # ip6 = IPAddress::IPv6::Mapped.new "::0d01:4403"
1218
+ #
1219
+ # ip6.to_string
1220
+ # #=> "::ffff:13.1.68.3"
1221
+ #
1222
+ def initialize(str)
1223
+ string, netmask = str.split("/")
1224
+ if string =~ /\./ # IPv4 in dotted decimal form
1225
+ @ipv4 = IPAddress::IPv4.extract(string)
1226
+ else # IPv4 in hex form
1227
+ groups = IPAddress::IPv6.groups(string)
1228
+ @ipv4 = IPAddress::IPv4.parse_u32((groups[-2]<< 16)+groups[-1])
1229
+ end
1230
+ super("::ffff:#{@ipv4.to_ipv6}/#{netmask}")
1231
+ end
1232
+
1233
+ #
1234
+ # Similar to IPv6#to_s, but prints out the IPv4 address
1235
+ # in dotted decimal format
1236
+ #
1237
+ # ip6 = IPAddress "::ffff:172.16.10.1/128"
1238
+ #
1239
+ # ip6.to_s
1240
+ # #=> "::ffff:172.16.10.1"
1241
+ #
1242
+ def to_s
1243
+ "::ffff:#{@ipv4.address}"
1244
+ end
1245
+
1246
+ #
1247
+ # Similar to IPv6#to_string, but prints out the IPv4 address
1248
+ # in dotted decimal format
1249
+ #
1250
+ #
1251
+ # ip6 = IPAddress "::ffff:172.16.10.1/128"
1252
+ #
1253
+ # ip6.to_string
1254
+ # #=> "::ffff:172.16.10.1/128"
1255
+ #
1256
+ def to_string
1257
+ "::ffff:#{@ipv4.address}/#@prefix"
1258
+ end
1259
+
1260
+ #
1261
+ # Checks if the IPv6 address is IPv4 mapped
1262
+ #
1263
+ # ip6 = IPAddress "::ffff:172.16.10.1/128"
1264
+ #
1265
+ # ip6.mapped?
1266
+ # #=> true
1267
+ #
1268
+ def mapped?
1269
+ true
1270
+ end
1271
+ end # class IPv6::Mapped
1272
+
1273
+ end # module IPAddress
1274
+