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,1204 @@
1
+ require 'ipaddress_2/prefix'
2
+
3
+ module IPAddress;
4
+ #
5
+ # =Name
6
+ #
7
+ # IPAddress::IPv4 - IP version 4 address manipulation library
8
+ #
9
+ # =Synopsis
10
+ #
11
+ # require 'ipaddress'
12
+ #
13
+ # =Description
14
+ #
15
+ # Class IPAddress::IPv4 is used to handle IPv4 type addresses.
16
+ #
17
+ class IPv4
18
+
19
+ include IPAddress
20
+ include Enumerable
21
+ include Comparable
22
+
23
+ #
24
+ # This Hash contains the prefix values for Classful networks
25
+ #
26
+ # Note that classes C, D and E will all have a default
27
+ # prefix of /24 or 255.255.255.0
28
+ #
29
+ CLASSFUL = {
30
+ /^0../ => 8, # Class A, from 0.0.0.0 to 127.255.255.255
31
+ /^10./ => 16, # Class B, from 128.0.0.0 to 191.255.255.255
32
+ /^110/ => 24 # Class C, D and E, from 192.0.0.0 to 255.255.255.254
33
+ }
34
+
35
+ #
36
+ # Regular expression to match an IPv4 address
37
+ #
38
+ REGEXP = Regexp.new(/((25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)/)
39
+
40
+ #
41
+ # Creates a new IPv4 address object.
42
+ #
43
+ # An IPv4 address can be expressed in any of the following forms:
44
+ #
45
+ # * "10.1.1.1/24": ip +address+ and +prefix+. This is the common and
46
+ # suggested way to create an object .
47
+ # * "10.1.1.1/255.255.255.0": ip +address+ and +netmask+. Although
48
+ # convenient sometimes, this format is less clear than the previous
49
+ # one.
50
+ # * "10.1.1.1": if the address alone is specified, the prefix will be
51
+ # set as default 32, also known as the host prefix
52
+ #
53
+ # Examples:
54
+ #
55
+ # # These two are the same
56
+ # ip = IPAddress::IPv4.new("10.0.0.1/24")
57
+ # ip = IPAddress("10.0.0.1/24")
58
+ #
59
+ # # These two are the same
60
+ # IPAddress::IPv4.new "10.0.0.1/8"
61
+ # IPAddress::IPv4.new "10.0.0.1/255.0.0.0"
62
+ #
63
+ def initialize(str)
64
+ raise ArgumentError, "Nil IP" unless str
65
+ ip, netmask = str.split("/")
66
+
67
+ # Check the ip and remove white space
68
+ if IPAddress.valid_ipv4?(ip)
69
+ @address = ip.strip
70
+ else
71
+ raise ArgumentError, "Invalid IP #{ip.inspect}"
72
+ end
73
+
74
+ # Check the netmask
75
+ if netmask # netmask is defined
76
+ netmask.strip!
77
+ if netmask =~ /^\d{1,2}$/ # netmask in cidr format
78
+ @prefix = Prefix32.new(netmask.to_i)
79
+ elsif IPAddress.valid_ipv4_netmask?(netmask) # netmask in IP format
80
+ @prefix = Prefix32.parse_netmask(netmask)
81
+ else # invalid netmask
82
+ raise ArgumentError, "Invalid netmask #{netmask}"
83
+ end
84
+ else # netmask is nil, reverting to defaul classful mask
85
+ @prefix = Prefix32.new(32)
86
+ end
87
+
88
+ # Array formed with the IP octets
89
+ @octets = @address.split(".").map{|i| i.to_i}
90
+ # 32 bits interger containing the address
91
+ @u32 = (@octets[0]<< 24) + (@octets[1]<< 16) + (@octets[2]<< 8) + (@octets[3])
92
+
93
+ @allocator = 0
94
+ end # def initialize
95
+
96
+ #
97
+ # Returns the address portion of the IPv4 object
98
+ # as a string.
99
+ #
100
+ # ip = IPAddress("172.16.100.4/22")
101
+ #
102
+ # ip.address
103
+ # #=> "172.16.100.4"
104
+ #
105
+ def address
106
+ @address
107
+ end
108
+
109
+ #
110
+ # When serializing to JSON format, just use the string representation
111
+ #
112
+ # ip = IPAddress("172.16.100.4/22")
113
+ #
114
+ # ip.as_json
115
+ # #=> "172.16.100.4/22"
116
+ #
117
+ def as_json
118
+ to_string
119
+ end
120
+
121
+ #
122
+ # Returns the prefix portion of the IPv4 object
123
+ # as a IPAddress::Prefix32 object
124
+ #
125
+ # ip = IPAddress("172.16.100.4/22")
126
+ #
127
+ # ip.prefix
128
+ # #=> 22
129
+ #
130
+ # ip.prefix.class
131
+ # #=> IPAddress::Prefix32
132
+ #
133
+ def prefix
134
+ @prefix
135
+ end
136
+
137
+ #
138
+ # Set a new prefix number for the object
139
+ #
140
+ # This is useful if you want to change the prefix
141
+ # to an object created with IPv4::parse_u32 or
142
+ # if the object was created using the classful
143
+ # mask.
144
+ #
145
+ # ip = IPAddress("172.16.100.4")
146
+ #
147
+ # puts ip
148
+ # #=> 172.16.100.4/16
149
+ #
150
+ # ip.prefix = 22
151
+ #
152
+ # puts ip
153
+ # #=> 172.16.100.4/22
154
+ #
155
+ def prefix=(num)
156
+ @prefix = Prefix32.new(num)
157
+ end
158
+
159
+ #
160
+ # Returns the address as an array of decimal values
161
+ #
162
+ # ip = IPAddress("172.16.100.4")
163
+ #
164
+ # ip.octets
165
+ # #=> [172, 16, 100, 4]
166
+ #
167
+ def octets
168
+ @octets
169
+ end
170
+
171
+ #
172
+ # Returns a string with the address portion of
173
+ # the IPv4 object
174
+ #
175
+ # ip = IPAddress("172.16.100.4/22")
176
+ #
177
+ # ip.to_s
178
+ # #=> "172.16.100.4"
179
+ #
180
+ def to_s
181
+ @address
182
+ end
183
+
184
+ #
185
+ # Returns a string with the IP address in canonical
186
+ # form.
187
+ #
188
+ # ip = IPAddress("172.16.100.4/22")
189
+ #
190
+ # ip.to_string
191
+ # #=> "172.16.100.4/22"
192
+ #
193
+ def to_string
194
+ "#@address/#@prefix"
195
+ end
196
+
197
+ #
198
+ # Returns the prefix as a string in IP format
199
+ #
200
+ # ip = IPAddress("172.16.100.4/22")
201
+ #
202
+ # ip.netmask
203
+ # #=> "255.255.252.0"
204
+ #
205
+ def netmask
206
+ @prefix.to_ip
207
+ end
208
+
209
+ #
210
+ # Like IPv4#prefix=, this method allow you to
211
+ # change the prefix / netmask of an IP address
212
+ # object.
213
+ #
214
+ # ip = IPAddress("172.16.100.4")
215
+ #
216
+ # puts ip
217
+ # #=> 172.16.100.4/16
218
+ #
219
+ # ip.netmask = "255.255.252.0"
220
+ #
221
+ # puts ip
222
+ # #=> 172.16.100.4/22
223
+ #
224
+ def netmask=(addr)
225
+ @prefix = Prefix32.parse_netmask(addr)
226
+ end
227
+
228
+ #
229
+ # Returns the address portion in unsigned
230
+ # 32 bits integer format.
231
+ #
232
+ # This method is identical to the C function
233
+ # inet_pton to create a 32 bits address family
234
+ # structure.
235
+ #
236
+ # ip = IPAddress("10.0.0.0/8")
237
+ #
238
+ # ip.to_i
239
+ # #=> 167772160
240
+ #
241
+ def u32
242
+ @u32
243
+ end
244
+ alias_method :to_i, :u32
245
+ alias_method :to_u32, :u32
246
+
247
+ #
248
+ # Returns the address portion in
249
+ # hex
250
+ #
251
+ # ip = IPAddress("10.0.0.0")
252
+ #
253
+ # ip.to_h
254
+ # #=> 0a000000
255
+ #
256
+ def hex(space=true)
257
+ "%.4x%.4x" % [to_u32].pack("N").unpack("nn")
258
+ end
259
+ alias_method :to_h, :hex
260
+ alias_method :to_hex, :hex
261
+
262
+ #
263
+ # Returns the address portion of an IPv4 object
264
+ # in a network byte order format.
265
+ #
266
+ # ip = IPAddress("172.16.10.1/24")
267
+ #
268
+ # ip.data
269
+ # #=> "\254\020\n\001"
270
+ #
271
+ # It is usually used to include an IP address
272
+ # in a data packet to be sent over a socket
273
+ #
274
+ # a = Socket.open(params) # socket details here
275
+ # ip = IPAddress("10.1.1.0/24")
276
+ # binary_data = ["Address: "].pack("a*") + ip.data
277
+ #
278
+ # # Send binary data
279
+ # a.puts binary_data
280
+ #
281
+ def data
282
+ [@u32].pack("N")
283
+ end
284
+
285
+ #
286
+ # Returns the octet specified by index
287
+ #
288
+ # ip = IPAddress("172.16.100.50/24")
289
+ #
290
+ # ip[0]
291
+ # #=> 172
292
+ # ip[1]
293
+ # #=> 16
294
+ # ip[2]
295
+ # #=> 100
296
+ # ip[3]
297
+ # #=> 50
298
+ #
299
+ def [](index)
300
+ @octets[index]
301
+ end
302
+ alias_method :octet, :[]
303
+
304
+ #
305
+ # Updated the octet specified at index
306
+ #
307
+ # ip = IPAddress("172.16.100.50/24")
308
+ # ip[2] = 200
309
+ #
310
+ # #=> #<IPAddress::IPv4:0x00000000000000 @address="172.16.200.1",
311
+ # #=> @prefix=32, @octets=[172, 16, 200, 1], @u32=2886780929>
312
+ #
313
+ def []=(index, value)
314
+ @octets[index] = value.to_i
315
+ initialize("#{@octets.join('.')}/#{prefix}")
316
+ end
317
+ alias_method :octet=, :[]=
318
+
319
+ #
320
+ # Returns the address portion of an IP in binary format,
321
+ # as a string containing a sequence of 0 and 1
322
+ #
323
+ # ip = IPAddress("127.0.0.1")
324
+ #
325
+ # ip.bits
326
+ # #=> "01111111000000000000000000000001"
327
+ #
328
+ def bits
329
+ data.unpack("B*").first
330
+ end
331
+
332
+ #
333
+ # Returns the broadcast address for the given IP.
334
+ #
335
+ # ip = IPAddress("172.16.10.64/24")
336
+ #
337
+ # ip.broadcast.to_s
338
+ # #=> "172.16.10.255"
339
+ #
340
+ def broadcast
341
+ case
342
+ when prefix <= 30
343
+ self.class.parse_u32(broadcast_u32, @prefix)
344
+ when prefix == 31
345
+ self.class.parse_u32(-1, @prefix)
346
+ when prefix == 32
347
+ return self
348
+ end
349
+ end
350
+
351
+ #
352
+ # Checks if the IP address is actually a network
353
+ #
354
+ # ip = IPAddress("172.16.10.64/24")
355
+ #
356
+ # ip.network?
357
+ # #=> false
358
+ #
359
+ # ip = IPAddress("172.16.10.64/26")
360
+ #
361
+ # ip.network?
362
+ # #=> true
363
+ #
364
+ def network?
365
+ (@prefix < 32) && (@u32 | @prefix.to_u32 == @prefix.to_u32)
366
+ end
367
+
368
+ #
369
+ # Returns a new IPv4 object with the network number
370
+ # for the given IP.
371
+ #
372
+ # ip = IPAddress("172.16.10.64/24")
373
+ #
374
+ # ip.network.to_s
375
+ # #=> "172.16.10.0"
376
+ #
377
+ def network
378
+ self.class.parse_u32(network_u32, @prefix)
379
+ end
380
+
381
+ #
382
+ # Returns a new IPv4 object with the
383
+ # first host IP address in the range.
384
+ #
385
+ # Example: given the 192.168.100.0/24 network, the first
386
+ # host IP address is 192.168.100.1.
387
+ #
388
+ # ip = IPAddress("192.168.100.0/24")
389
+ #
390
+ # ip.first.to_s
391
+ # #=> "192.168.100.1"
392
+ #
393
+ # The object IP doesn't need to be a network: the method
394
+ # automatically gets the network number from it
395
+ #
396
+ # ip = IPAddress("192.168.100.50/24")
397
+ #
398
+ # ip.first.to_s
399
+ # #=> "192.168.100.1"
400
+ #
401
+ def first
402
+ case
403
+ when prefix <= 30
404
+ self.class.parse_u32(network_u32+1, @prefix)
405
+ when prefix == 31
406
+ self.class.parse_u32(network_u32, @prefix)
407
+ when prefix == 32
408
+ return self
409
+ end
410
+ end
411
+
412
+ #
413
+ # Like its sibling method IPv4#first, this method
414
+ # returns a new IPv4 object with the
415
+ # last host IP address in the range.
416
+ #
417
+ # Example: given the 192.168.100.0/24 network, the last
418
+ # host IP address is 192.168.100.254
419
+ #
420
+ # ip = IPAddress("192.168.100.0/24")
421
+ #
422
+ # ip.last.to_s
423
+ # #=> "192.168.100.254"
424
+ #
425
+ # The object IP doesn't need to be a network: the method
426
+ # automatically gets the network number from it
427
+ #
428
+ # ip = IPAddress("192.168.100.50/24")
429
+ #
430
+ # ip.last.to_s
431
+ # #=> "192.168.100.254"
432
+ #
433
+ def last
434
+ case
435
+ when prefix <= 30
436
+ self.class.parse_u32(broadcast_u32-1, @prefix)
437
+ when prefix == 31
438
+ self.class.parse_u32(broadcast_u32, @prefix)
439
+ when prefix == 32
440
+ return self
441
+ end
442
+ end
443
+
444
+ #
445
+ # Iterates over all the hosts IP addresses for the given
446
+ # network (or IP address).
447
+ #
448
+ # ip = IPAddress("10.0.0.1/29")
449
+ #
450
+ # ip.each_host do |i|
451
+ # p i.to_s
452
+ # end
453
+ # #=> "10.0.0.1"
454
+ # #=> "10.0.0.2"
455
+ # #=> "10.0.0.3"
456
+ # #=> "10.0.0.4"
457
+ # #=> "10.0.0.5"
458
+ # #=> "10.0.0.6"
459
+ #
460
+ def each_host
461
+ (network_u32+1..broadcast_u32-1).each do |i|
462
+ yield self.class.parse_u32(i, @prefix)
463
+ end
464
+ end
465
+
466
+ #
467
+ # Iterates over all the IP addresses for the given
468
+ # network (or IP address).
469
+ #
470
+ # The object yielded is a new IPv4 object created
471
+ # from the iteration.
472
+ #
473
+ # ip = IPAddress("10.0.0.1/29")
474
+ #
475
+ # ip.each do |i|
476
+ # p i.address
477
+ # end
478
+ # #=> "10.0.0.0"
479
+ # #=> "10.0.0.1"
480
+ # #=> "10.0.0.2"
481
+ # #=> "10.0.0.3"
482
+ # #=> "10.0.0.4"
483
+ # #=> "10.0.0.5"
484
+ # #=> "10.0.0.6"
485
+ # #=> "10.0.0.7"
486
+ #
487
+ def each
488
+ (network_u32..broadcast_u32).each do |i|
489
+ yield self.class.parse_u32(i, @prefix)
490
+ end
491
+ end
492
+
493
+ #
494
+ # Returns the successor to the IP address
495
+ #
496
+ # Example:
497
+ #
498
+ # ip = IPAddress("192.168.45.23/16")
499
+ #
500
+ # ip.succ.to_string
501
+ # => "192.168.45.24/16"
502
+ #
503
+ def succ
504
+ self.class.new("#{IPAddress.ntoa(to_u32.succ % 0x100000000)}/#{prefix}")
505
+ end
506
+ alias_method :next, :succ
507
+
508
+ #
509
+ # Returns the predecessor to the IP address
510
+ #
511
+ # Example:
512
+ #
513
+ # ip = IPAddress("192.168.45.23/16")
514
+ #
515
+ # ip.pred.to_string
516
+ # => "192.168.45.22/16"
517
+ #
518
+ def pred
519
+ self.class.new("#{IPAddress.ntoa(to_u32.pred % 0x100000000)}/#{prefix}")
520
+ end
521
+
522
+ #
523
+ # Spaceship operator to compare IPv4 objects
524
+ #
525
+ # Comparing IPv4 addresses is useful to ordinate
526
+ # them into lists that match our intuitive
527
+ # perception of ordered IP addresses.
528
+ #
529
+ # The first comparison criteria is the u32 value.
530
+ # For example, 10.100.100.1 will be considered
531
+ # to be less than 172.16.0.1, because, in a ordered list,
532
+ # we expect 10.100.100.1 to come before 172.16.0.1.
533
+ #
534
+ # The second criteria, in case two IPv4 objects
535
+ # have identical addresses, is the prefix. An higher
536
+ # prefix will be considered greater than a lower
537
+ # prefix. This is because we expect to see
538
+ # 10.100.100.0/24 come before 10.100.100.0/25.
539
+ #
540
+ # Example:
541
+ #
542
+ # ip1 = IPAddress "10.100.100.1/8"
543
+ # ip2 = IPAddress "172.16.0.1/16"
544
+ # ip3 = IPAddress "10.100.100.1/16"
545
+ #
546
+ # ip1 < ip2
547
+ # #=> true
548
+ # ip1 > ip3
549
+ # #=> false
550
+ #
551
+ # [ip1,ip2,ip3].sort.map{|i| i.to_string}
552
+ # #=> ["10.100.100.1/8","10.100.100.1/16","172.16.0.1/16"]
553
+ #
554
+ def <=>(oth)
555
+ return nil unless oth.is_a?(self.class)
556
+ return prefix <=> oth.prefix if to_u32 == oth.to_u32
557
+ to_u32 <=> oth.to_u32
558
+ end
559
+
560
+ #
561
+ # Returns the number of IP addresses included
562
+ # in the network. It also counts the network
563
+ # address and the broadcast address.
564
+ #
565
+ # ip = IPAddress("10.0.0.1/29")
566
+ #
567
+ # ip.size
568
+ # #=> 8
569
+ #
570
+ def size
571
+ 2 ** @prefix.host_prefix
572
+ end
573
+
574
+ #
575
+ # Returns an array with the IP addresses of
576
+ # all the hosts in the network.
577
+ #
578
+ # ip = IPAddress("10.0.0.1/29")
579
+ #
580
+ # ip.hosts.map {|i| i.address}
581
+ # #=> ["10.0.0.1",
582
+ # #=> "10.0.0.2",
583
+ # #=> "10.0.0.3",
584
+ # #=> "10.0.0.4",
585
+ # #=> "10.0.0.5",
586
+ # #=> "10.0.0.6"]
587
+ #
588
+ def hosts
589
+ to_a[1..-2]
590
+ end
591
+
592
+ #
593
+ # Returns the network number in Unsigned 32bits format
594
+ #
595
+ # ip = IPAddress("10.0.0.1/29")
596
+ #
597
+ # ip.network_u32
598
+ # #=> 167772160
599
+ #
600
+ def network_u32
601
+ @u32 & @prefix.to_u32
602
+ end
603
+
604
+ #
605
+ # Returns the broadcast address in Unsigned 32bits format
606
+ #
607
+ # ip = IPaddress("10.0.0.1/29")
608
+ #
609
+ # ip.broadcast_u32
610
+ # #=> 167772167
611
+ #
612
+ def broadcast_u32
613
+ network_u32 + size - 1
614
+ end
615
+
616
+ #
617
+ # Checks whether a subnet includes the given IP address.
618
+ #
619
+ # Accepts an IPAddress::IPv4 object.
620
+ #
621
+ # ip = IPAddress("192.168.10.100/24")
622
+ #
623
+ # addr = IPAddress("192.168.10.102/24")
624
+ #
625
+ # ip.include? addr
626
+ # #=> true
627
+ #
628
+ # ip.include? IPAddress("172.16.0.48/16")
629
+ # #=> false
630
+ #
631
+ def include?(oth)
632
+ @prefix <= oth.prefix and network_u32 == (oth.to_u32 & @prefix.to_u32)
633
+ end
634
+
635
+ #
636
+ # Checks whether a subnet includes all the
637
+ # given IPv4 objects.
638
+ #
639
+ # ip = IPAddress("192.168.10.100/24")
640
+ #
641
+ # addr1 = IPAddress("192.168.10.102/24")
642
+ # addr2 = IPAddress("192.168.10.103/24")
643
+ #
644
+ # ip.include_all?(addr1,addr2)
645
+ # #=> true
646
+ #
647
+ def include_all?(*others)
648
+ others.all? {|oth| include?(oth)}
649
+ end
650
+
651
+ #
652
+ # Checks if an IPv4 address objects belongs
653
+ # to a private network RFC1918
654
+ #
655
+ # Example:
656
+ #
657
+ # ip = IPAddress "10.1.1.1/24"
658
+ # ip.private?
659
+ # #=> true
660
+ #
661
+ def private?
662
+ [self.class.new("10.0.0.0/8"),
663
+ self.class.new("172.16.0.0/12"),
664
+ self.class.new("192.168.0.0/16")].any? {|i| i.include? self}
665
+ end
666
+
667
+ #
668
+ # Checks if an IPv4 address objects belongs
669
+ # to a multicast network RFC3171
670
+ #
671
+ # Example:
672
+ #
673
+ # ip = IPAddress "224.0.0.0/4"
674
+ # ip.multicast?
675
+ # #=> true
676
+ #
677
+ def multicast?
678
+ [self.class.new("224.0.0.0/4")].any? {|i| i.include? self}
679
+ end
680
+
681
+ #
682
+ # Checks if an IPv4 address objects belongs
683
+ # to a loopback network RFC1122
684
+ #
685
+ # Example:
686
+ #
687
+ # ip = IPAddress "127.0.0.1"
688
+ # ip.loopback?
689
+ # #=> true
690
+ #
691
+ def loopback?
692
+ [self.class.new("127.0.0.0/8")].any? {|i| i.include? self}
693
+ end
694
+
695
+ #
696
+ # Checks if an IPv4 address objects belongs
697
+ # to a link-local network RFC3927
698
+ #
699
+ # Example:
700
+ #
701
+ # ip = IPAddress "169.254.0.1"
702
+ # ip.link_local?
703
+ # #=> true
704
+ #
705
+ def link_local?
706
+ [self.class.new("169.254.0.0/16")].any? {|i| i.include? self}
707
+ end
708
+
709
+ #
710
+ # Returns the IP address in in-addr.arpa format
711
+ # for DNS lookups
712
+ #
713
+ # ip = IPAddress("172.16.100.50/24")
714
+ #
715
+ # ip.reverse
716
+ # #=> "50.100.16.172.in-addr.arpa"
717
+ #
718
+ def reverse
719
+ @octets.reverse.join(".") + ".in-addr.arpa"
720
+ end
721
+ alias_method :arpa, :reverse
722
+
723
+ #
724
+ # Return a list of IP's between @address
725
+ # and the supplied IP
726
+ #
727
+ # ip = IPAddress("172.16.100.51/32")
728
+ #
729
+ # ip.to("172.16.100.100")
730
+ # #=> ["172.16.100.51",
731
+ # #=> "172.16.100.52",
732
+ # #=> ...
733
+ # #=> "172.16.100.99",
734
+ # #=> "172.16.100.100"]
735
+ #
736
+ def to(e)
737
+ unless e.is_a? IPAddress::IPv4
738
+ e = IPv4.new(e)
739
+ end
740
+
741
+ Range.new(@u32, e.to_u32).map{|i| IPAddress.ntoa(i) }
742
+ end
743
+ #
744
+ # Splits a network into different subnets
745
+ #
746
+ # If the IP Address is a network, it can be divided into
747
+ # multiple networks. If +self+ is not a network, this
748
+ # method will calculate the network from the IP and then
749
+ # subnet it.
750
+ #
751
+ # If +subnets+ is an power of two number, the resulting
752
+ # networks will be divided evenly from the supernet.
753
+ #
754
+ # network = IPAddress("172.16.10.0/24")
755
+ #
756
+ # network / 4 # implies map{|i| i.to_string}
757
+ # #=> ["172.16.10.0/26",
758
+ # #=> "172.16.10.64/26",
759
+ # #=> "172.16.10.128/26",
760
+ # #=> "172.16.10.192/26"]
761
+ #
762
+ # If +num+ is any other number, the supernet will be
763
+ # divided into some networks with a even number of hosts and
764
+ # other networks with the remaining addresses.
765
+ #
766
+ # network = IPAddress("172.16.10.0/24")
767
+ #
768
+ # network / 3 # implies map{|i| i.to_string}
769
+ # #=> ["172.16.10.0/26",
770
+ # #=> "172.16.10.64/26",
771
+ # #=> "172.16.10.128/25"]
772
+ #
773
+ # Returns an array of IPv4 objects
774
+ #
775
+ def split(subnets=2)
776
+ unless (1..(2**@prefix.host_prefix)).include? subnets
777
+ raise ArgumentError, "Value #{subnets} out of range"
778
+ end
779
+ networks = subnet(newprefix(subnets))
780
+ until networks.size == subnets
781
+ networks = sum_first_found(networks)
782
+ end
783
+ return networks
784
+ end
785
+ alias_method :/, :split
786
+
787
+ #
788
+ # Returns a new IPv4 object from the supernetting
789
+ # of the instance network.
790
+ #
791
+ # Supernetting is similar to subnetting, except
792
+ # that you getting as a result a network with a
793
+ # smaller prefix (bigger host space). For example,
794
+ # given the network
795
+ #
796
+ # ip = IPAddress("172.16.10.0/24")
797
+ #
798
+ # you can supernet it with a new /23 prefix
799
+ #
800
+ # ip.supernet(23).to_string
801
+ # #=> "172.16.10.0/23"
802
+ #
803
+ # However if you supernet it with a /22 prefix, the
804
+ # network address will change:
805
+ #
806
+ # ip.supernet(22).to_string
807
+ # #=> "172.16.8.0/22"
808
+ #
809
+ # If +new_prefix+ is less than 1, returns 0.0.0.0/0
810
+ #
811
+ def supernet(new_prefix)
812
+ raise ArgumentError, "New prefix must be smaller than existing prefix" if new_prefix >= @prefix.to_i
813
+ return self.class.new("0.0.0.0/0") if new_prefix < 1
814
+ return self.class.new(@address+"/#{new_prefix}").network
815
+ end
816
+
817
+ #
818
+ # This method implements the subnetting function
819
+ # similar to the one described in RFC3531.
820
+ #
821
+ # By specifying a new prefix, the method calculates
822
+ # the network number for the given IPv4 object
823
+ # and calculates the subnets associated to the new
824
+ # prefix.
825
+ #
826
+ # For example, given the following network:
827
+ #
828
+ # ip = IPAddress "172.16.10.0/24"
829
+ #
830
+ # we can calculate the subnets with a /26 prefix
831
+ #
832
+ # ip.subnet(26).map{&:to_string)
833
+ # #=> ["172.16.10.0/26", "172.16.10.64/26",
834
+ # "172.16.10.128/26", "172.16.10.192/26"]
835
+ #
836
+ # The resulting number of subnets will of course always be
837
+ # a power of two.
838
+ #
839
+ def subnet(subprefix)
840
+ unless ((@prefix.to_i)..32).include? subprefix
841
+ raise ArgumentError, "New prefix must be between #@prefix and 32"
842
+ end
843
+ Array.new(2**(subprefix-@prefix.to_i)) do |i|
844
+ self.class.parse_u32(network_u32+(i*(2**(32-subprefix))), subprefix)
845
+ end
846
+ end
847
+
848
+ #
849
+ # Returns the difference between two IP addresses
850
+ # in unsigned int 32 bits format
851
+ #
852
+ # Example:
853
+ #
854
+ # ip1 = IPAddress("172.16.10.0/24")
855
+ # ip2 = IPAddress("172.16.11.0/24")
856
+ #
857
+ # puts ip1 - ip2
858
+ # #=> 256
859
+ #
860
+ def -(oth)
861
+ return (to_u32 - oth.to_u32).abs
862
+ end
863
+
864
+ #
865
+ # Returns a new IPv4 object which is the result
866
+ # of the summarization, if possible, of the two
867
+ # objects
868
+ #
869
+ # Example:
870
+ #
871
+ # ip1 = IPAddress("172.16.10.1/24")
872
+ # ip2 = IPAddress("172.16.11.2/24")
873
+ #
874
+ # p (ip1 + ip2).map {|i| i.to_string}
875
+ # #=> ["172.16.10.0/23"]
876
+ #
877
+ # If the networks are not contiguous, returns
878
+ # the two network numbers from the objects
879
+ #
880
+ # ip1 = IPAddress("10.0.0.1/24")
881
+ # ip2 = IPAddress("10.0.2.1/24")
882
+ #
883
+ # p (ip1 + ip2).map {|i| i.to_string}
884
+ # #=> ["10.0.0.0/24","10.0.2.0/24"]
885
+ #
886
+ def +(oth)
887
+ aggregate(*[self,oth].sort.map{|i| i.network})
888
+ end
889
+
890
+ #
891
+ # Checks whether the ip address belongs to a
892
+ # RFC 791 CLASS A network, no matter
893
+ # what the subnet mask is.
894
+ #
895
+ # Example:
896
+ #
897
+ # ip = IPAddress("10.0.0.1/24")
898
+ #
899
+ # ip.a?
900
+ # #=> true
901
+ #
902
+ def a?
903
+ CLASSFUL.key(8) === bits
904
+ end
905
+
906
+ #
907
+ # Checks whether the ip address belongs to a
908
+ # RFC 791 CLASS B network, no matter
909
+ # what the subnet mask is.
910
+ #
911
+ # Example:
912
+ #
913
+ # ip = IPAddress("172.16.10.1/24")
914
+ #
915
+ # ip.b?
916
+ # #=> true
917
+ #
918
+ def b?
919
+ CLASSFUL.key(16) === bits
920
+ end
921
+
922
+ #
923
+ # Checks whether the ip address belongs to a
924
+ # RFC 791 CLASS C network, no matter
925
+ # what the subnet mask is.
926
+ #
927
+ # Example:
928
+ #
929
+ # ip = IPAddress("192.168.1.1/30")
930
+ #
931
+ # ip.c?
932
+ # #=> true
933
+ #
934
+ def c?
935
+ CLASSFUL.key(24) === bits
936
+ end
937
+
938
+ #
939
+ # Return the ip address in a format compatible
940
+ # with the IPv6 Mapped IPv4 addresses
941
+ #
942
+ # Example:
943
+ #
944
+ # ip = IPAddress("172.16.10.1/24")
945
+ #
946
+ # ip.to_ipv6
947
+ # #=> "ac10:0a01"
948
+ #
949
+ def to_ipv6
950
+ "%.4x:%.4x" % [to_u32].pack("N").unpack("nn")
951
+ end
952
+
953
+ #
954
+ # Creates a new IPv4 object from an
955
+ # unsigned 32bits integer.
956
+ #
957
+ # ip = IPAddress::IPv4::parse_u32(167772160)
958
+ #
959
+ # ip.prefix = 8
960
+ # ip.to_string
961
+ # #=> "10.0.0.0/8"
962
+ #
963
+ # The +prefix+ parameter is optional:
964
+ #
965
+ # ip = IPAddress::IPv4::parse_u32(167772160, 8)
966
+ #
967
+ # ip.to_string
968
+ # #=> "10.0.0.0/8"
969
+ #
970
+ def self.parse_u32(u32, prefix=32)
971
+ self.new([u32].pack("N").unpack("C4").join(".")+"/#{prefix}")
972
+ end
973
+
974
+ #
975
+ # Creates a new IPv4 object from binary data,
976
+ # like the one you get from a network stream.
977
+ #
978
+ # For example, on a network stream the IP 172.16.0.1
979
+ # is represented with the binary "\254\020\n\001".
980
+ #
981
+ # ip = IPAddress::IPv4::parse_data "\254\020\n\001"
982
+ # ip.prefix = 24
983
+ #
984
+ # ip.to_string
985
+ # #=> "172.16.10.1/24"
986
+ #
987
+ def self.parse_data(str, prefix=32)
988
+ self.new(str.unpack("C4").join(".")+"/#{prefix}")
989
+ end
990
+
991
+ #
992
+ # Extract an IPv4 address from a string and
993
+ # returns a new object
994
+ #
995
+ # Example:
996
+ #
997
+ # str = "foobar172.16.10.1barbaz"
998
+ # ip = IPAddress::IPv4::extract str
999
+ #
1000
+ # ip.to_s
1001
+ # #=> "172.16.10.1"
1002
+ #
1003
+ def self.extract(str)
1004
+ self.new REGEXP.match(str).to_s
1005
+ end
1006
+
1007
+ #
1008
+ # Summarization (or aggregation) is the process when two or more
1009
+ # networks are taken together to check if a supernet, including all
1010
+ # and only these networks, exists. If it exists then this supernet
1011
+ # is called the summarized (or aggregated) network.
1012
+ #
1013
+ # It is very important to understand that summarization can only
1014
+ # occur if there are no holes in the aggregated network, or, in other
1015
+ # words, if the given networks fill completely the address space
1016
+ # of the supernet. So the two rules are:
1017
+ #
1018
+ # 1) The aggregate network must contain +all+ the IP addresses of the
1019
+ # original networks;
1020
+ # 2) The aggregate network must contain +only+ the IP addresses of the
1021
+ # original networks;
1022
+ #
1023
+ # A few examples will help clarify the above. Let's consider for
1024
+ # instance the following two networks:
1025
+ #
1026
+ # ip1 = IPAddress("172.16.10.0/24")
1027
+ # ip2 = IPAddress("172.16.11.0/24")
1028
+ #
1029
+ # These two networks can be expressed using only one IP address
1030
+ # network if we change the prefix. Let Ruby do the work:
1031
+ #
1032
+ # IPAddress::IPv4::summarize(ip1,ip2).to_s
1033
+ # #=> "172.16.10.0/23"
1034
+ #
1035
+ # We note how the network "172.16.10.0/23" includes all the addresses
1036
+ # specified in the above networks, and (more important) includes
1037
+ # ONLY those addresses.
1038
+ #
1039
+ # If we summarized +ip1+ and +ip2+ with the following network:
1040
+ #
1041
+ # "172.16.0.0/16"
1042
+ #
1043
+ # we would have satisfied rule #1 above, but not rule #2. So "172.16.0.0/16"
1044
+ # is not an aggregate network for +ip1+ and +ip2+.
1045
+ #
1046
+ # If it's not possible to compute a single aggregated network for all the
1047
+ # original networks, the method returns an array with all the aggregate
1048
+ # networks found. For example, the following four networks can be
1049
+ # aggregated in a single /22:
1050
+ #
1051
+ # ip1 = IPAddress("10.0.0.1/24")
1052
+ # ip2 = IPAddress("10.0.1.1/24")
1053
+ # ip3 = IPAddress("10.0.2.1/24")
1054
+ # ip4 = IPAddress("10.0.3.1/24")
1055
+ #
1056
+ # IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).to_string
1057
+ # #=> "10.0.0.0/22",
1058
+ #
1059
+ # But the following networks can't be summarized in a single network:
1060
+ #
1061
+ # ip1 = IPAddress("10.0.1.1/24")
1062
+ # ip2 = IPAddress("10.0.2.1/24")
1063
+ # ip3 = IPAddress("10.0.3.1/24")
1064
+ # ip4 = IPAddress("10.0.4.1/24")
1065
+ #
1066
+ # IPAddress::IPv4::summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
1067
+ # #=> ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
1068
+ #
1069
+ def self.summarize(*args)
1070
+ # one network? no need to summarize
1071
+ return [args.first.network] if args.size == 1
1072
+
1073
+ i = 0
1074
+ result = args.dup.sort.map{|ip| ip.network}
1075
+ while i < result.size-1
1076
+ sum = result[i] + result[i+1]
1077
+ result[i..i+1] = sum.first if sum.size == 1
1078
+ i += 1
1079
+ end
1080
+
1081
+ result.flatten!
1082
+ if result.size == args.size
1083
+ # nothing more to summarize
1084
+ return result
1085
+ else
1086
+ # keep on summarizing
1087
+ return self.summarize(*result)
1088
+ end
1089
+ end
1090
+
1091
+ #
1092
+ # Creates a new IPv4 address object by parsing the
1093
+ # address in a classful way.
1094
+ #
1095
+ # Classful addresses have a fixed netmask based on the
1096
+ # class they belong to:
1097
+ #
1098
+ # * Class A, from 0.0.0.0 to 127.255.255.255
1099
+ # * Class B, from 128.0.0.0 to 191.255.255.255
1100
+ # * Class C, D and E, from 192.0.0.0 to 255.255.255.254
1101
+ #
1102
+ # Example:
1103
+ #
1104
+ # ip = IPAddress::IPv4.parse_classful "10.0.0.1"
1105
+ #
1106
+ # ip.netmask
1107
+ # #=> "255.0.0.0"
1108
+ # ip.a?
1109
+ # #=> true
1110
+ #
1111
+ # Note that classes C, D and E will all have a default
1112
+ # prefix of /24 or 255.255.255.0
1113
+ #
1114
+ def self.parse_classful(ip)
1115
+ if IPAddress.valid_ipv4?(ip)
1116
+ address = ip.strip
1117
+ else
1118
+ raise ArgumentError, "Invalid IP #{ip.inspect}"
1119
+ end
1120
+ prefix = CLASSFUL.find{|h,k| h === ("%.8b" % address.to_i)}.last
1121
+ self.new "#{address}/#{prefix}"
1122
+ end
1123
+
1124
+ #
1125
+ # Allocates a new ip from the current subnet. Optional skip parameter
1126
+ # can be used to skip addresses.
1127
+ #
1128
+ # Will raise StopIteration exception when all addresses have been allocated
1129
+ #
1130
+ # Example:
1131
+ #
1132
+ # ip = IPAddress("10.0.0.0/24")
1133
+ # ip.allocate
1134
+ # #=> "10.0.0.1/24"
1135
+ # ip.allocate
1136
+ # #=> "10.0.0.2/24"
1137
+ # ip.allocate(2)
1138
+ # #=> "10.0.0.5/24"
1139
+ #
1140
+ #
1141
+ # Uses an internal @allocator which tracks the state of allocated
1142
+ # addresses.
1143
+ #
1144
+ def allocate(skip=0)
1145
+ @allocator += 1 + skip
1146
+
1147
+ next_ip = network_u32+@allocator
1148
+ if next_ip > broadcast_u32+1
1149
+ raise StopIteration
1150
+ end
1151
+ self.class.parse_u32(network_u32+@allocator, @prefix)
1152
+ end
1153
+
1154
+ #
1155
+ # Finds the adjacent block to a subnet.
1156
+ #
1157
+ # Example:
1158
+ #
1159
+ # ip = IPAddress("10.0.0.0/24")
1160
+ # ip.find_adjacent_subnet
1161
+ # #=> "10.0.1.0/24"
1162
+ #
1163
+ def find_adjacent_subnet
1164
+ return false if prefix == 0
1165
+ current_subnet = to_string
1166
+ self.prefix = @prefix - 1
1167
+ (split.map{|i| i.to_string} - [current_subnet])[0]
1168
+ end
1169
+
1170
+ #
1171
+ # private methods
1172
+ #
1173
+ private
1174
+
1175
+ # Tweaked to remove the #upto(32)
1176
+ def newprefix(num)
1177
+ return @prefix + (Math::log2(num).ceil )
1178
+ end
1179
+
1180
+ def sum_first_found(arr)
1181
+ dup = arr.dup.reverse
1182
+ dup.each_with_index do |obj,i|
1183
+ a = [self.class.summarize(obj,dup[i+1])].flatten
1184
+ if a.size == 1
1185
+ dup[i..i+1] = a
1186
+ return dup.reverse
1187
+ end
1188
+ end
1189
+ return dup.reverse
1190
+ end
1191
+
1192
+ def aggregate(ip1,ip2)
1193
+ return [ip1] if ip1.include? ip2
1194
+
1195
+ snet = ip1.supernet(ip1.prefix-1)
1196
+ if snet.include_all?(ip1, ip2) && ((ip1.size + ip2.size) == snet.size)
1197
+ return [snet]
1198
+ else
1199
+ return [ip1, ip2]
1200
+ end
1201
+ end
1202
+ end # class IPv4
1203
+ end # module IPAddress
1204
+