blackwinter-ipaddress 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/ipaddress.rb ADDED
@@ -0,0 +1,967 @@
1
+ #
2
+ # = IPAddress
3
+ #
4
+ # A ruby library to manipulate IPv4 and IPv6 addresses
5
+ #
6
+ #
7
+ # Package:: IPAddress
8
+ # Author:: Marco Ceresa <ceresa@ieee.org>
9
+ # License:: Ruby License
10
+ #
11
+ #--
12
+ #
13
+ #++
14
+
15
+ require 'ipaddress/conversions'
16
+ require 'ipaddress/lazy'
17
+
18
+ class IPAddress
19
+
20
+ include Enumerable
21
+ include Comparable
22
+
23
+ include Conversions
24
+ extend Conversions
25
+
26
+ include Lazy
27
+
28
+ VERSION = '0.8.0'
29
+ NAME = 'IPAddress'
30
+ GEM = 'ipaddress'
31
+ AUTHORS = ['Marco Ceresa <ceresa@ieee.org>']
32
+
33
+ class << self
34
+
35
+ #
36
+ # Parse the argument string to create a new
37
+ # IPv4, IPv6 or Mapped IP object
38
+ #
39
+ # ip = IPAddress.parse "172.16.10.1/24"
40
+ # ip6 = IPAddress.parse "2001:db8::8:800:200c:417a/64"
41
+ # ip_mapped = IPAddress.parse "::ffff:172.16.10.1/128"
42
+ #
43
+ # All the object created will be instances of the
44
+ # correct class:
45
+ #
46
+ # ip.class
47
+ # #=> IPAddress::IPv4
48
+ # ip6.class
49
+ # #=> IPAddress::IPv6
50
+ # ip_mapped.class
51
+ # #=> IPAddress::IPv6::Mapped
52
+ #
53
+ def parse(str)
54
+ case str
55
+ when /:.+\./ then IPv6::Mapped.new(str)
56
+ when /\./ then IPv4.new(str)
57
+ when /:/ then IPv6.new(str)
58
+ else raise ArgumentError, "Unknown IP Address #{str.inspect}"
59
+ end
60
+ end
61
+
62
+ def parse_i(version, i, prefix = nil)
63
+ case version
64
+ when 4
65
+ IPv4.parse_i(i, prefix || IPv4::MAX_PREFIX)
66
+ when 6
67
+ IPv6.parse_i(i, prefix || IPv6::MAX_PREFIX).instance_eval { mapped || self }
68
+ else
69
+ raise ArgumentError, "IP protocol version not supported: #{version.inspect}"
70
+ end
71
+ end
72
+
73
+ #
74
+ # Checks if the given string is a valid IP address,
75
+ # either IPv4 or IPv6
76
+ #
77
+ # Example:
78
+ #
79
+ # IPAddress::valid? "2002::1"
80
+ # #=> true
81
+ #
82
+ # IPAddress::valid? "10.0.0.256"
83
+ # #=> false
84
+ #
85
+ def valid?(addr)
86
+ valid_ipv4?(addr) || valid_ipv6?(addr)
87
+ end
88
+
89
+ #
90
+ # Checks if the given string is a valid IPv4 address
91
+ #
92
+ # Example:
93
+ #
94
+ # IPAddress::valid_ipv4? "2002::1"
95
+ # #=> false
96
+ #
97
+ # IPAddress::valid_ipv4? "172.16.10.1"
98
+ # #=> true
99
+ #
100
+ def valid_ipv4?(addr)
101
+ IPv4::RE === addr
102
+ end
103
+
104
+ #
105
+ # Checks if the argument is a valid IPv4 netmask
106
+ # expressed in dotted decimal format.
107
+ #
108
+ # IPAddress.valid_ipv4_netmask? "255.255.0.0"
109
+ # #=> true
110
+ #
111
+ def valid_ipv4_netmask?(addr)
112
+ valid_ipv4?(addr) && addr2bits(addr) !~ /01/
113
+ end
114
+
115
+ #
116
+ # Checks if the given string is a valid IPv6 address
117
+ #
118
+ # Example:
119
+ #
120
+ # IPAddress::valid_ipv6? "2002::1"
121
+ # #=> true
122
+ #
123
+ # IPAddress::valid_ipv6? "2002::1::2"
124
+ # #=> false
125
+ #
126
+ def valid_ipv6?(addr)
127
+ IPv6::RE === addr
128
+ end
129
+
130
+ #
131
+ # Summarization (or aggregation) is the process when two or more
132
+ # networks are taken together to check if a supernet, including all
133
+ # and only these networks, exists. If it exists then this supernet
134
+ # is called the summarized (or aggregated) network.
135
+ #
136
+ # It is very important to understand that summarization can only
137
+ # occur if there are no holes in the aggregated network, or, in other
138
+ # words, if the given networks fill completely the address space
139
+ # of the supernet. So the two rules are:
140
+ #
141
+ # 1) The aggregate network must contain +all+ the IP addresses of the
142
+ # original networks;
143
+ # 2) The aggregate network must contain +only+ the IP addresses of the
144
+ # original networks;
145
+ #
146
+ # A few examples will help clarify the above. Let's consider for
147
+ # instance the following two networks:
148
+ #
149
+ # ip1 = IPAddress("172.16.10.0/24")
150
+ # ip2 = IPAddress("172.16.11.0/24")
151
+ #
152
+ # These two networks can be expressed using only one IP address
153
+ # network if we change the prefix. Let Ruby do the work:
154
+ #
155
+ # IPAddress::IPv4.summarize(ip1,ip2).map { |i| i.to_string }
156
+ # #=> ["172.16.10.0/23"]
157
+ #
158
+ # We note how the network "172.16.10.0/23" includes all the addresses
159
+ # specified in the above networks, and (more important) includes
160
+ # ONLY those addresses.
161
+ #
162
+ # If we summarized +ip1+ and +ip2+ with the following network:
163
+ #
164
+ # "172.16.0.0/16"
165
+ #
166
+ # we would have satisfied rule #1 above, but not rule #2. So "172.16.0.0/16"
167
+ # is not an aggregate network for +ip1+ and +ip2+.
168
+ #
169
+ # If it's not possible to compute a single aggregated network for all the
170
+ # original networks, the method returns an array with all the aggregate
171
+ # networks found. For example, the following four networks can be
172
+ # aggregated in a single /22:
173
+ #
174
+ # ip1 = IPAddress("10.0.0.1/24")
175
+ # ip2 = IPAddress("10.0.1.1/24")
176
+ # ip3 = IPAddress("10.0.2.1/24")
177
+ # ip4 = IPAddress("10.0.3.1/24")
178
+ #
179
+ # IPAddress::IPv4.summarize(ip1,ip2,ip3,ip4).map { |i| i.to_string }
180
+ # #=> ["10.0.0.0/22"]
181
+ #
182
+ # But the following networks can't be summarized in a single network:
183
+ #
184
+ # ip1 = IPAddress("10.0.1.1/24")
185
+ # ip2 = IPAddress("10.0.2.1/24")
186
+ # ip3 = IPAddress("10.0.3.1/24")
187
+ # ip4 = IPAddress("10.0.4.1/24")
188
+ #
189
+ # IPAddress::IPv4.summarize(ip1,ip2,ip3,ip4).map { |i| i.to_string }
190
+ # #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
191
+ #
192
+ def summarize(*nets)
193
+ nets.sort!.map! { |i| i.network }
194
+ return nets unless nets.size > 1
195
+
196
+ loop {
197
+ i, f = -1, false
198
+
199
+ while i < nets.size - 2
200
+ i1, i2 = nets[i += 1, 2]
201
+
202
+ if s = i1.proper_supernet(i2)
203
+ nets[i, 2], f = s, true
204
+ end
205
+ end
206
+
207
+ return nets unless f
208
+ }
209
+ end
210
+
211
+ def subtract(a, *b)
212
+ subtract!(a.is_a?(Array) ? a.dup : [a], *b)
213
+ end
214
+
215
+ def subtract!(a, *b)
216
+ raise TypeError, "Array expected, got #{a.class}" unless a.is_a?(Array)
217
+
218
+ a.uniq!; b.flatten!; b.uniq!
219
+ c, d = [], b.map { |i| i.boundaries }
220
+
221
+ loop {
222
+ a.delete_if { |i|
223
+ b.any? { |j| j.include?(i) } || if i.overlap_i?(*d)
224
+ (n = i.prefix.next) ? c.concat(i.subnet(n)) : c << i
225
+ end
226
+ }
227
+
228
+ c.empty? ? break : a.concat(c); c.clear
229
+ }
230
+
231
+ a.replace(summarize(*a)).sort!
232
+ end
233
+
234
+ private
235
+
236
+ def instantiate(&block)
237
+ instance = allocate
238
+ instance.instance_eval(&block)
239
+ instance
240
+ end
241
+
242
+ #
243
+ # Deprecate method
244
+ #
245
+ def deprecate(message = nil) # :nodoc:
246
+ warn("DEPRECATION WARNING: #{message || 'You are using deprecated behavior which will be removed from the next major or minor release.'}")
247
+ end
248
+
249
+ end
250
+
251
+ #
252
+ # True if the object is an IPv4 address
253
+ #
254
+ # ip = IPAddress("192.168.10.100/24")
255
+ #
256
+ # ip.ipv4?
257
+ # #-> true
258
+ #
259
+ def ipv4?
260
+ is_a?(IPv4)
261
+ end
262
+
263
+ #
264
+ # True if the object is an IPv6 address
265
+ #
266
+ # ip = IPAddress("192.168.10.100/24")
267
+ #
268
+ # ip.ipv6?
269
+ # #-> false
270
+ #
271
+ def ipv6?
272
+ is_a?(IPv6)
273
+ end
274
+
275
+ #
276
+ # Returns a string with the IP address in canonical
277
+ # form.
278
+ #
279
+ # ip = IPAddress("172.16.100.4/22")
280
+ #
281
+ # ip.to_string
282
+ # #=> "172.16.100.4/22"
283
+ #
284
+ # ip6 = IPAddress("2001:0db8:0000:0000:0008:0800:200c:417a/64")
285
+ #
286
+ # ip6.to_string
287
+ # #=> "2001:db8::8:800:200c:417a/64"
288
+ #
289
+ def to_string
290
+ "#{to_s}/#{prefix}"
291
+ end
292
+
293
+ def inspect
294
+ "#{self.class}@#{to_string}"
295
+ end
296
+
297
+ #
298
+ # Returns the address portion of an IP in binary format,
299
+ # as a string containing a sequence of 0 and 1
300
+ #
301
+ # ip = IPAddress("127.0.0.1")
302
+ #
303
+ # ip.bits
304
+ # #=> "01111111000000000000000000000001"
305
+ #
306
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a")
307
+ #
308
+ # ip6.bits
309
+ # #=> "0010000000000001000011011011100000 [...] "
310
+ #
311
+ def bits
312
+ lazy(:bits) { data2bits(data) }
313
+ end
314
+
315
+ #
316
+ # Checks if the IP address is actually a network
317
+ #
318
+ # ip = IPAddress("172.16.10.64/24")
319
+ #
320
+ # ip.network?
321
+ # #=> false
322
+ #
323
+ # ip = IPAddress("172.16.10.64/26")
324
+ #
325
+ # ip.network?
326
+ # #=> true
327
+ #
328
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a/64")
329
+ #
330
+ # ip6.network?
331
+ # #=> false
332
+ #
333
+ # ip6 = IPAddress("2001:db8:8:800::/64")
334
+ #
335
+ # ip6.network?
336
+ # #=> true
337
+ #
338
+ def network?
339
+ lazy(:network_p) { i = prefix.to_i; to_i | i == i }
340
+ end
341
+
342
+ #
343
+ # Returns a new IPv4/IPv6 object with the network number
344
+ # for the given IP.
345
+ #
346
+ # ip = IPAddress("172.16.10.64/24")
347
+ #
348
+ # ip.network.to_s
349
+ # #=> "172.16.10.0"
350
+ #
351
+ # ip6 = IPAddress("2001:db8:1:1:1:1:1:1/32")
352
+ #
353
+ # ip6.network.to_string
354
+ # #=> "2001:db8::/32"
355
+ #
356
+ def network
357
+ lazy(:network, false) { network? ? self : at(0) }
358
+ end
359
+
360
+ #
361
+ # Returns the network number in Unsigned 32bits/128bits format
362
+ #
363
+ # ip = IPAddress("10.0.0.1/29")
364
+ #
365
+ # ip.network_u32
366
+ # #=> 167772160
367
+ #
368
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a/64")
369
+ #
370
+ # ip6.network_u128
371
+ # #=> 42540766411282592856903984951653826560
372
+ #
373
+ def network_i
374
+ lazy(:network_i) { to_i & prefix.to_i }
375
+ end
376
+
377
+ #
378
+ # Returns the broadcast address for the given IP.
379
+ #
380
+ # ip = IPAddress("172.16.10.64/24")
381
+ #
382
+ # ip.broadcast.to_s
383
+ # #=> "172.16.10.255"
384
+ #
385
+ def broadcast
386
+ lazy(:broadcast, false) { at(-1) }
387
+ end
388
+
389
+ #
390
+ # Returns the broadcast address in Unsigned 32bits/128bits format
391
+ #
392
+ # ip = IPaddress("10.0.0.1/29")
393
+ #
394
+ # ip.broadcast_u32
395
+ # #=> 167772167
396
+ #
397
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a/64")
398
+ #
399
+ # ip6.broadcast_u128
400
+ # #=> 42540766411282592875350729025363378175
401
+ #
402
+ # Please note that there is no Broadcast concept in IPv6
403
+ # addresses as in IPv4 addresses, and this method is just
404
+ # a helper to other functions.
405
+ #
406
+ def broadcast_i
407
+ lazy(:broadcast_i) { network_i + size - 1 }
408
+ end
409
+
410
+ #
411
+ # Returns the number of IP addresses included
412
+ # in the network. It also counts the network
413
+ # address and the broadcast address.
414
+ #
415
+ # ip = IPAddress("10.0.0.1/29")
416
+ #
417
+ # ip.size
418
+ # #=> 8
419
+ #
420
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a/64")
421
+ #
422
+ # ip6.size
423
+ # #=> 18446744073709551616
424
+ #
425
+ def size
426
+ lazy(:size) { 2 ** prefix.host_prefix }
427
+ end
428
+
429
+ #
430
+ # Set a new prefix number for the object
431
+ #
432
+ # This is useful if you want to change the prefix
433
+ # to an object created with IPv4.parse_u32/IPv6.parse_u128
434
+ # or if the object was created using the classful mask/
435
+ # the default prefix of 128 bits.
436
+ #
437
+ # ip = IPAddress("172.16.100.4")
438
+ #
439
+ # ip.to_string
440
+ # #=> 172.16.100.4/16
441
+ #
442
+ # ip2 = ip.new_prefix(22)
443
+ #
444
+ # ip2.to_string
445
+ # #=> 172.16.100.4/22
446
+ #
447
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a")
448
+ #
449
+ # ip6.to_string
450
+ # #=> "2001:db8::8:800:200c:417a/128"
451
+ #
452
+ # ip2 = ip6.new_prefix(64)
453
+ #
454
+ # ip2.to_string
455
+ # #=> "2001:db8::8:800:200c:417a/64"
456
+ #
457
+ def new_prefix(prefix)
458
+ self.class.parse_i(to_i, prefix)
459
+ end
460
+
461
+ #
462
+ # Checks whether a subnet includes the given IP address.
463
+ #
464
+ # Accepts an IPAddress::IPv4 object.
465
+ #
466
+ # ip = IPAddress("192.168.10.100/24")
467
+ # addr = IPAddress("192.168.10.102/24")
468
+ #
469
+ # ip.include?(addr)
470
+ # #=> true
471
+ #
472
+ # ip.include?(IPAddress("172.16.0.48/16"))
473
+ # #=> false
474
+ #
475
+ # ip6 = IPAddress("2001:db8::8:800:200c:417a/64")
476
+ # addr = IPAddress("2001:db8::8:800:200c:1/128")
477
+ #
478
+ # ip6.include?(addr)
479
+ # #=> true
480
+ #
481
+ # ip6.include?(IPAddress("2001:db8:1::8:800:200c:417a/76"))
482
+ # #=> false
483
+ #
484
+ def include?(other)
485
+ prefix <= other.prefix && network_i == other.to_i & prefix.to_i
486
+ end
487
+
488
+ #
489
+ # Checks whether a subnet includes all the
490
+ # given IP objects.
491
+ #
492
+ # ip = IPAddress("192.168.10.100/24")
493
+ #
494
+ # addr1 = IPAddress("192.168.10.102/24")
495
+ # addr2 = IPAddress("192.168.10.103/24")
496
+ #
497
+ # ip.include_all?(addr1, addr2)
498
+ # #=> true
499
+ #
500
+ def include_all?(*other)
501
+ other.all? { |i| include?(i) }
502
+ end
503
+
504
+ def include_exactly?(*other)
505
+ s = size
506
+ other.each { |i| s -= i.size }
507
+ s == 0 && include_all?(*other)
508
+ end
509
+
510
+ def overlap?(*other)
511
+ overlap_i?(*other.map! { |i| i.boundaries })
512
+ end
513
+
514
+ def overlap_i?(*other)
515
+ f, l = boundaries
516
+ !other.all? { |i, j| l < i || f > j }
517
+ end
518
+
519
+ #
520
+ # Splits a network into different subnets
521
+ #
522
+ # If the IP Address is a network, it can be divided into
523
+ # multiple networks. If +self+ is not a network, this
524
+ # method will calculate the network from the IP and then
525
+ # subnet it.
526
+ #
527
+ # If +subnets+ is an power of two number, the resulting
528
+ # networks will be divided evenly from the supernet.
529
+ #
530
+ # network = IPAddress("172.16.10.0/24")
531
+ #
532
+ # (network / 4).map { |i| i.to_string }
533
+ # #=> ["172.16.10.0/26",
534
+ # "172.16.10.64/26",
535
+ # "172.16.10.128/26",
536
+ # "172.16.10.192/26"]
537
+ #
538
+ # If +num+ is any other number, the supernet will be
539
+ # divided into some networks with a even number of hosts and
540
+ # other networks with the remaining addresses.
541
+ #
542
+ # network = IPAddress("172.16.10.0/24")
543
+ #
544
+ # (network / 3).map { |i| i.to_string }
545
+ # #=> ["172.16.10.0/26",
546
+ # "172.16.10.64/26",
547
+ # "172.16.10.128/25"]
548
+ #
549
+ # Returns an array of IPv4 objects
550
+ #
551
+ def split(subnets = 2)
552
+ unless (1..size).include?(subnets)
553
+ raise ArgumentError, "Value #{subnets} out of range"
554
+ end
555
+
556
+ networks = subnet(prefix + Math.log2(subnets).ceil)
557
+
558
+ until networks.size == subnets
559
+ networks.reverse!.each_with_index { |n, i|
560
+ if s = n.proper_supernet(networks[i + 1])
561
+ networks[i, 2] = s
562
+ break
563
+ end
564
+ }
565
+
566
+ networks.reverse!
567
+ end
568
+
569
+ networks
570
+ end
571
+
572
+ alias_method :/, :split
573
+
574
+ #
575
+ # Returns a new IPv4 object from the supernetting
576
+ # of the instance network.
577
+ #
578
+ # Supernetting is similar to subnetting, except
579
+ # that you getting as a result a network with a
580
+ # smaller prefix (bigger host space). For example,
581
+ # given the network
582
+ #
583
+ # ip = IPAddress("172.16.10.0/24")
584
+ #
585
+ # you can supernet it with a new /23 prefix
586
+ #
587
+ # ip.supernet(23).to_string
588
+ # #=> "172.16.10.0/23"
589
+ #
590
+ # However if you supernet it with a /22 prefix, the
591
+ # network address will change:
592
+ #
593
+ # ip.supernet(22).to_string
594
+ # #=> "172.16.8.0/22"
595
+ #
596
+ # If +new_prefix+ is less than 1, returns 0.0.0.0/0
597
+ #
598
+ def supernet(num)
599
+ new_prefix(prefix.superprefix(num)).network
600
+ end
601
+
602
+ def exact_supernet(*other)
603
+ s = supernet(prefix - 1)
604
+ s if s.include_exactly?(self, *other)
605
+ end
606
+
607
+ def proper_supernet(*other)
608
+ include_all?(*other) ? self : exact_supernet(*other)
609
+ end
610
+
611
+ #
612
+ # This method implements the subnetting function
613
+ # similar to the one described in RFC3531.
614
+ #
615
+ # By specifying a new prefix, the method calculates
616
+ # the network number for the given IPv4 object
617
+ # and calculates the subnets associated to the new
618
+ # prefix.
619
+ #
620
+ # For example, given the following network:
621
+ #
622
+ # ip = IPAddress("172.16.10.0/24")
623
+ #
624
+ # we can calculate the subnets with a /26 prefix
625
+ #
626
+ # ip.subnet(26).map { |i| i.to_string }
627
+ # #=> ["172.16.10.0/26", "172.16.10.64/26",
628
+ # "172.16.10.128/26", "172.16.10.192/26"]
629
+ #
630
+ # The resulting number of subnets will of course always be
631
+ # a power of two.
632
+ #
633
+ def subnet(num)
634
+ n, m, s = network_i, *prefix.subprefix(num)
635
+ Array.new(s) { |i| self.class.parse_i(n + (i * m), num) }
636
+ end
637
+
638
+ #
639
+ # Returns the difference between two IP addresses
640
+ # in unsigned int 32/128 bits format
641
+ #
642
+ # Example:
643
+ #
644
+ # ip1 = IPAddress("172.16.10.0/24")
645
+ # ip2 = IPAddress("172.16.11.0/24")
646
+ #
647
+ # ip1.distance(ip2)
648
+ # #=> 256
649
+ #
650
+ def distance(other)
651
+ (to_i - other.to_i).abs
652
+ end
653
+
654
+ def subtract(*other)
655
+ self.class.subtract(self, *other)
656
+ end
657
+
658
+ alias_method :-, :subtract
659
+
660
+ #
661
+ # Returns a new IPv4 object which is the result
662
+ # of the summarization, if possible, of the two
663
+ # objects
664
+ #
665
+ # Example:
666
+ #
667
+ # ip1 = IPAddress("172.16.10.1/24")
668
+ # ip2 = IPAddress("172.16.11.2/24")
669
+ #
670
+ # p (ip1 + ip2).map {|i| i.to_string}
671
+ # #=> ["172.16.10.0/23"]
672
+ #
673
+ # If the networks are not contiguous, returns
674
+ # the two network numbers from the objects
675
+ #
676
+ # ip1 = IPAddress("10.0.0.1/24")
677
+ # ip2 = IPAddress("10.0.2.1/24")
678
+ #
679
+ # p (ip1 + ip2).map {|i| i.to_string}
680
+ # #=> ["10.0.0.0/24","10.0.2.0/24"]
681
+ #
682
+ def summarize(other)
683
+ self.class.summarize(self, other)
684
+ end
685
+
686
+ alias_method :+, :summarize
687
+
688
+ def range
689
+ lazy(:range) { network_i..broadcast_i }
690
+ end
691
+
692
+ def range_i
693
+ lazy(:range_i) { range.to_a }
694
+ end
695
+
696
+ def boundaries
697
+ lazy(:boundaries) { [(r = range).first, r.last] }
698
+ end
699
+
700
+ def each_i(first = nil, last = nil)
701
+ f, l = boundaries
702
+ [first || f, f].max.upto([last || l, l].min) { |i| yield i }
703
+ self
704
+ end
705
+
706
+ #
707
+ # Iterates over all the IP addresses for the given
708
+ # network (or IP address).
709
+ #
710
+ # The object yielded is a new IPv4/IPv6 object created
711
+ # from the iteration.
712
+ #
713
+ # ip = IPAddress("10.0.0.1/29")
714
+ #
715
+ # ip.each do |i|
716
+ # p i.address
717
+ # end
718
+ # #=> "10.0.0.0"
719
+ # #=> "10.0.0.1"
720
+ # #=> "10.0.0.2"
721
+ # #=> "10.0.0.3"
722
+ # #=> "10.0.0.4"
723
+ # #=> "10.0.0.5"
724
+ # #=> "10.0.0.6"
725
+ # #=> "10.0.0.7"
726
+ #
727
+ # ip6 = IPAddress("2001:db8::4/125")
728
+ #
729
+ # ip6.each do |i|
730
+ # p i.compressed
731
+ # end
732
+ # #=> "2001:db8::"
733
+ # #=> "2001:db8::1"
734
+ # #=> "2001:db8::2"
735
+ # #=> "2001:db8::3"
736
+ # #=> "2001:db8::4"
737
+ # #=> "2001:db8::5"
738
+ # #=> "2001:db8::6"
739
+ # #=> "2001:db8::7"
740
+ #
741
+ # WARNING: if the host portion is very large, this method
742
+ # can be very slow and possibly hang your system!
743
+ #
744
+ def each(*args)
745
+ f = prefix
746
+ each_i(*args) { |i| yield self.class.parse_i(i, f) }
747
+ end
748
+
749
+ #
750
+ # Iterates over all the hosts IP addresses for the given
751
+ # network (or IP address).
752
+ #
753
+ # ip = IPAddress("10.0.0.1/29")
754
+ #
755
+ # ip.each_host do |i|
756
+ # p i.to_s
757
+ # end
758
+ # #=> "10.0.0.1"
759
+ # #=> "10.0.0.2"
760
+ # #=> "10.0.0.3"
761
+ # #=> "10.0.0.4"
762
+ # #=> "10.0.0.5"
763
+ # #=> "10.0.0.6"
764
+ #
765
+ def each_host
766
+ f, l = boundaries
767
+ each(f + 1, l - 1) { |i| yield i }
768
+ end
769
+
770
+ def at(index)
771
+ r = range
772
+
773
+ index += index < 0 ? r.last + 1 : r.first
774
+ each(index) { |i| return i } if r.include?(index)
775
+
776
+ nil
777
+ end
778
+
779
+ #
780
+ # Returns a new IPv4/IPv6 object with the
781
+ # first host IP address in the range.
782
+ #
783
+ # Example: given the 192.168.100.0/24 network, the first
784
+ # host IP address is 192.168.100.1.
785
+ #
786
+ # ip = IPAddress("192.168.100.0/24")
787
+ #
788
+ # ip.first.to_s
789
+ # #=> "192.168.100.1"
790
+ #
791
+ # The object IP doesn't need to be a network: the method
792
+ # automatically gets the network number from it
793
+ #
794
+ # ip = IPAddress("192.168.100.50/24")
795
+ #
796
+ # ip.first.to_s
797
+ # #=> "192.168.100.1"
798
+ #
799
+ def first
800
+ lazy(:first, false) { at(1) }
801
+ end
802
+
803
+ #
804
+ # Like its sibling method IPv4#first/IPv6#first, this method
805
+ # returns a new IPv4/IPv6 object with the
806
+ # last host IP address in the range.
807
+ #
808
+ # Example: given the 192.168.100.0/24 network, the last
809
+ # host IP address is 192.168.100.254
810
+ #
811
+ # ip = IPAddress("192.168.100.0/24")
812
+ #
813
+ # ip.last.to_s
814
+ # #=> "192.168.100.254"
815
+ #
816
+ # The object IP doesn't need to be a network: the method
817
+ # automatically gets the network number from it
818
+ #
819
+ # ip = IPAddress("192.168.100.50/24")
820
+ #
821
+ # ip.last.to_s
822
+ # #=> "192.168.100.254"
823
+ #
824
+ def last
825
+ lazy(:last, false) { at(-2) }
826
+ end
827
+
828
+ #
829
+ # Returns an array with the IP addresses of
830
+ # all the hosts in the network.
831
+ #
832
+ # ip = IPAddress("10.0.0.1/29")
833
+ #
834
+ # ip.hosts.map { |i| i.address }
835
+ # #=> ["10.0.0.1",
836
+ # #=> "10.0.0.2",
837
+ # #=> "10.0.0.3",
838
+ # #=> "10.0.0.4",
839
+ # #=> "10.0.0.5",
840
+ # #=> "10.0.0.6"]
841
+ #
842
+ def hosts
843
+ lazy(:hosts) { hosts = []; each_host { |i| hosts << i }; hosts }
844
+ end
845
+
846
+ def mapped
847
+ IPv6::Mapped.new(to_string) if ipv4? || mapped?
848
+ end
849
+
850
+ #
851
+ # Spaceship operator to compare IPv4/IPv6 objects
852
+ #
853
+ # Comparing IPv4/IPv6 addresses is useful to ordinate
854
+ # them into lists that match our intuitive
855
+ # perception of ordered IP addresses.
856
+ #
857
+ # The first comparison criteria is the u32/u128 value.
858
+ # For example, 10.100.100.1 will be considered
859
+ # to be less than 172.16.0.1, because, in a ordered list,
860
+ # we expect 10.100.100.1 to come before 172.16.0.1;
861
+ # 2001:db8:1::1 will be considered
862
+ # to be less than 2001:db8:2::1, because, in a ordered list,
863
+ # we expect 2001:db8:1::1 to come before 2001:db8:2::1.
864
+ #
865
+ # The second criteria, in case two IPv4/IPv6 objects
866
+ # have identical addresses, is the prefix. A higher
867
+ # prefix will be considered greater than a lower
868
+ # prefix. This is because we expect to see
869
+ # 10.100.100.0/24 come before 10.100.100.0/25;
870
+ # 2001:db8:1::1/64 before 2001:db8:1::1/65.
871
+ #
872
+ # Example:
873
+ #
874
+ # ip1 = IPAddress("10.100.100.1/8")
875
+ # ip2 = IPAddress("172.16.0.1/16")
876
+ # ip3 = IPAddress("10.100.100.1/16")
877
+ #
878
+ # ip1 < ip2
879
+ # #=> true
880
+ # ip1 > ip3
881
+ # #=> false
882
+ #
883
+ # [ip1,ip2,ip3].sort.map { |i| i.to_string }
884
+ # #=> ["10.100.100.1/8","10.100.100.1/16","172.16.0.1/16"]
885
+ #
886
+ # ip1 = IPAddress("2001:db8:1::1/64")
887
+ # ip2 = IPAddress("2001:db8:2::1/64")
888
+ # ip3 = IPAddress("2001:db8:1::1/65")
889
+ #
890
+ # ip1 < ip2
891
+ # #=> true
892
+ # ip1 < ip3
893
+ # #=> false
894
+ #
895
+ # [ip1,ip2,ip3].sort.map { |i| i.to_string }
896
+ # #=> ["2001:db8:1::1/64","2001:db8:1::1/65","2001:db8:2::1/64"]
897
+ #
898
+ def <=>(other)
899
+ [to_i, prefix] <=> [other.to_i, other.prefix]
900
+ end
901
+
902
+ def hash
903
+ lazy(:hash) { [to_i, prefix.hash].hash }
904
+ end
905
+
906
+ alias_method :eql?, :==
907
+
908
+ private
909
+
910
+ def split_ip_and_netmask(str, validate = true)
911
+ ip_and_netmask = str.split('/')
912
+
913
+ if validate && !self.class.valid_ip?(ip = ip_and_netmask.first)
914
+ raise ArgumentError, "Invalid IP #{ip.inspect}"
915
+ else
916
+ ip_and_netmask
917
+ end
918
+ end
919
+
920
+ end
921
+
922
+ #
923
+ # IPAddress is a wrapper method built around
924
+ # IPAddress's library classes. Its purpose is to
925
+ # make you independent from the type of IP address
926
+ # you're going to use.
927
+ #
928
+ # For example, instead of creating the three types
929
+ # of IP addresses using their own contructors
930
+ #
931
+ # ip = IPAddress::IPv4.new "172.16.10.1/24"
932
+ # ip6 = IPAddress::IPv6.new "2001:db8::8:800:200c:417a/64"
933
+ # ip_mapped = IPAddress::IPv6::Mapped "::ffff:172.16.10.1/128"
934
+ #
935
+ # you can just use the IPAddress wrapper:
936
+ #
937
+ # ip = IPAddress "172.16.10.1/24"
938
+ # ip6 = IPAddress "2001:db8::8:800:200c:417a/64"
939
+ # ip_mapped = IPAddress "::ffff:172.16.10.1/128"
940
+ #
941
+ # All the objects created will be instances of the
942
+ # correct class:
943
+ #
944
+ # ip.class
945
+ # #=> IPAddress::IPv4
946
+ # ip6.class
947
+ # #=> IPAddress::IPv6
948
+ # ip_mapped.class
949
+ # #=> IPAddress::IPv6::Mapped
950
+ #
951
+ def IPAddress(str)
952
+ IPAddress.parse(str)
953
+ end
954
+
955
+ #
956
+ # Compatibility with Ruby 1.8
957
+ #
958
+ if RUBY_VERSION < '1.9'
959
+ def Math.log2(n) # :nodoc:
960
+ log(n) / log(2)
961
+ end
962
+ end
963
+
964
+ require 'ipaddress/prefix'
965
+
966
+ require 'ipaddress/ipv4'
967
+ require 'ipaddress/ipv6'